zoukankan      html  css  js  c++  java
  • acc 视频解密笔记

    active player 是北京网动(http://www.iactive.com.cn/)出品的多媒体课件播放器。很好用。在国内的教育行业有较为广泛的应用。时代光华、华图网校等课件都是用这种播放器来播放的。

     
    手中的课件使用了网络验证。二话不说先抓包。结果如下:
    代码

    GET /verify/verify.asp?username=12345678910&password=123456&guid=7USC9W34-2Q90-VBG2-7A45-28UXZY9W9S1T&enc_mode=2&enc_seed=619823 HTTP/1.1

    User-Agent: ACPlayer

    Host: http://www.******.net/

    Cache-Control: no-cache



    HTTP/1.1 200 OK

    Date: Wed, 23 Dec 2009 04:24:20 GMT

    Server: Microsoft-IIS/6.0

    X-Powered-By: ASP.NET

    Content-Length: 137

    Content-Type: text/html

    Cache-control: private



    ID:36ca8f6009ba4d8481f13d4a77a0c41f33fe43cdaf494710a542988b38dca2990cb7d371183241019ad2d5dc167eaa89be3cfc70aacd45ddac49ed82dbdf3a58;INFO:


    http 包很简单。应答包中,有一个ID字串,可能这就是 key 了。

    用错误的用户名和密码试试:

    代码
    GET /verify/verify.asp?username=123213&password=213123&guid=7USC9W34-2Q90-VBG2-7A45-28UXZY9W9S1T&enc_mode=2&enc_seed=1399442 HTTP/1.1

    User-Agent: ACPlayer

    Host: www.htexam.net

    Cache-Control: no-cache

    Cookie: 92o_smile=1D1D0D1; rtime=3; ltime=1259506761000; cnzz_eid=52227509-1258510252-; 92o_cookietime=2592000; ASPSESSIONIDSARSBCTD=BAIGHELANAJMNENJDHCFJPHC; xsxscdb_cookietime=2592000; DOYOO_USER_ID=c114da7eaa134aaa99fbccc26c548645; DVC_25924=1



    HTTP/1.1 200 OK

    Date: Wed, 23 Dec 2009 04:37:19 GMT

    Server: Microsoft-IIS/6.0

    X-Powered-By: ASP.NET

    Content-Length: 30

    Content-Type: text/html

    Cache-control: private



    ID:0;INFO:....................

    以上,info 是一个二进制字串。其 hex值为:

    d3 c3 bb a7 c3 fb bb f2 d5 df c3 dc c2 eb b4 ed ce f3 a3 a1                                         ...

    共 20个字节。

    对应的提示信息是 10个中文字符:

    用户名或者密码错误!

    故以上info的两个字节代码一个汉字字节。应该是 gbk 编码吧。

    所以,关键的返回的信息应该就是id 串了。  在上面的字串中,id 是一个 128 位的字串,其字符范围是 [0-9][a-f]。估计是一些字节的 16进制视图。那么,这个id 应该是一个 64byte的二进制串。

    36 ca 8f 60 09 ba 4d 84 81 f1 3d 4a 77 a0 c4 1f 33 fe 43 cd 
    af 49 47 10 a5 42 98 8b 38 dc a2 99 0c b7 d3 71 18 32 41 01 
    9a d2 d5 dc 16 7e aa 89 be 3c fc 70 aa cd 45 dd ac 49 ed 82 
    db df 3a 58


    祭出 ida。载入程序后 debug 起来:

    CDialog::OnOK(void)    .text 0047EDEA 00000006 R . . . . . .

    呵呵,看到程序中就这一个 ok 按钮。当然要在这里下断点了。
    右键,"add breakpoint"。运行后,程序果然断了下来。
    回到程序领空。

    0044600D   .  6A 00         push    0
    0044600F   .  6A 00         push    0
    00446011   .  68 02000084   push    84000002
    00446016   .  6A 01         push    1
    00446018   .  8B85 58FFFFFF mov     eax, dword ptr [ebp-A8]
    0044601E   .  50            push    eax
    0044601F   .  8B4D DC       mov     ecx, dword ptr [ebp-24]
    00446022   .  E8 CB8E0300   call    <jmp.&MFC42.#5207_CInternetSession::OpenURL>       ;  连接网络
    00446027   .  8985 54FFFFFF mov     dword ptr [ebp-AC], eax                            ;  // CHttpFile*

    openurl 的第一个参数就是 我们上面截获的 get 串。往上查找 get 字串的组织过程:

    代码
    004474B5      FF15 00DD4800 call    dword ptr [<&WINMM.timeGetTime>]                 ;  WINMM.timeGetTime
    ......

    004474E2   .  52            push    edx ; edx是开机到现在的秒数
    004474E3   .  68 44034A00   push    004A0344                                         ;  ASCII "%d"
    004474E8   .  8D45 C8       lea     eax, dword ptr [ebp-38]
    004474EB   .  50            push    eax
    004474EC   .  E8 7BF90300   call    <jmp.&MFC42.#2818_CString::Format>               ;  [ebp-38]指向开机秒数的字串
    ......

    00447524   .  52            push    edx
    00447525   .  8B85 60FFFFFF mov     eax, dword ptr [ebp-A0]
    0044752B   .  8B88 8C000000 mov     ecx, dword ptr [eax+8C]                          ; [00100fb8+8c]
    00447531   .  51            push    ecx                                              ;  guid
    00447532   .  8B15 C0334A00 mov     edx, dword ptr [4A33C0]                          ;  用户名
    00447538   .  52            push    edx
    00447539   .  A1 C4334A00   mov     eax, dword ptr [4A33C4]                          ;  密码
    0044753E   .  50            push    eax
    0044753F   .  8B4D 08       mov     ecx, dword ptr [ebp+8]
    00447542   .  E8 79DCFBFF   call    004051C0                                         ;  **[ebp+8]
    00447547   .  50            push    eax                                              ;  [ebp-14] 带形参的 get字串
    00447548   .  8D4D EC       lea     ecx, dword ptr [ebp-14]                          ;  [ebp-14] 组织好的 get 字串
    0044754B   .  51            push    ecx
    0044754C   .  E8 1BF90300   call    <jmp.&MFC42.#2818_CString::Format>               ;  填充 get 字串中的形参

    经过多次跟踪发现,get 串中,只有 enc_seed 字段的值是变的。而从上面的代码分析知,enc_seed 的值是首地址保存在 [ebp-38] 中的一个字串。这个字串是开机到现在的秒数的 string  表达。而其 int 值保存在了 [ebp-1c]中。

    向下查看函数中与 [ebp-38] 或 [ebp-1c] 相关的代码:

    id 与 timegettime值的计算
    0044789C   > \8B55 C4       mov     edx, dword ptr [ebp-3C]
    0044789F   .  52            push    edx
    004478A0   .  E8 3CFC0200   call    004774E1                                         ;  对 id 进行计算。提取到一个整数。关键算法?
    004478A5   .  83C4 04       add     esp, 4
    004478A8   .  8985 0CFFFFFF mov     dword ptr [ebp-F4], eax
    004478AE   .  8B85 0CFFFFFF mov     eax, dword ptr [ebp-F4]
    004478B4   .  8945 E0       mov     dword ptr [ebp-20], eax                          ;  [ebp -20] ID 的运算值
    004478B7   .  8B4D E0       mov     ecx, dword ptr [ebp-20]
    004478BA   .  334D E4       xor     ecx, dword ptr [ebp-1C]
    004478BD   .  894D E0       mov     dword ptr [ebp-20], ecx

     以上代码中,首地址为 edx 的 id 字串,经函数 004774e1解密后,与保存在 [ebp-1c] 中的时间函数做 xor 运算。得到一个整数值保存在 [ebp-20]中。再往下看这个函数知,函数只将 [ebp-20] 作为函数返回值返回。因为这个函数中没有涉及栈帧以外的变量来处理 id 值,所以我们推测,id 字串已经浓缩为 [ebp-20]。原字串已经不再有用。

    程序从函数 返回到 acplayer.004469c6:

    acplayer.004469c6
    00446D70  |.  E8 0B060000   call    00447380                                         ;  连接网络并获得返回值的摘要
    00446D75  |.  8B8D 78FBFFFF mov     ecx, dword ptr [ebp-488]
    00446D7B  |.  8981 18020000 mov     dword ptr [ecx+218], eax
    00446D81  |.  8B95 78FBFFFF mov     edx, dword ptr [ebp-488]
    00446D87  |.  83BA 18020000>cmp     dword ptr [edx+218], 0                           ;  [00100fb8+ 218] id xor time 的值
    00446D8E  |.  75 2A         jnz     short 00446DBA

     返回值保存到了栈帧以外的变量中 [00100fb8+ 218] 。这就是解密的 key 了吧?

    在 00100fb8+ 218 处下内存访问断点。f9,程序一路小跑。停下来了:

    004463CD   > \C745 EC 4C454>mov     dword ptr [ebp-14], 524E454C                     ;  "LENR"
    004463D4   .  8B85 1CFBFFFF mov     eax, dword ptr [ebp-4E4]
    004463DA   .  83B8 1C020000>cmp     dword ptr [eax+21C], 0
    004463E1   .  74 12         je      short 004463F5
    004463E3   .  8B8D 1CFBFFFF mov     ecx, dword ptr [ebp-4E4]
    004463E9   .  8B55 EC       mov     edx, dword ptr [ebp-14]
    004463EC   .  3391 18020000 xor     edx, dword ptr [ecx+218]

    此处 [00100fb8+ 218] 的操作是:解密字串 "LENR"。

    查找程序中所有对此处的引用。一种办法是下内存访问断点。另一种办法是使用 ida 的脚本。

    祭出《加密与解密》, 124 页。

    “一个简单并且有效的办法,是在整个代码里搜索访问 0xxxxxxx--0xxxxxxx 这段缓存区的 mov 指令。这时 IDA 强大就体现出来了。用IDA 打开如下脚本,就可将读取指定内存的代码列出了”。

    书中提供了一个脚本   getasm.idc

    // filename : getasm.idc
    // code by DarkNessOut

    static getasm( from, to, range1, range2  )
    {
        auto ea, cmd, fp,deta, opcode;
        fp 
    = fopen( "c:\\code.txt""w" );
        
    for( ea= from;ea < to; )


        {
          cmd 
    = GetMnem( ea );
            
    if ( strstr( cmd, "mov" ) == 0 || strstr( cmd, "lea" ) == 0 )
            {
               opcode 
    = Dword( NextNotTail( ea ) - 4 );
               
    if ( opcode< 0 )
               {
                   opcode 
    = ~opcode;
                   opcode
    ++;
               }
               Message( 
    "-> %08X %08X\n", ea, opcode );
               
    if( opcode >= range1 && opcode <= range2 )
               {
                   deta 
    = opcode - range1;
                   fprintf( fp, 
    "%08X %s    // + 0x%04X\n  ", ea, GetDisasm( ea ), deta );
                   MakeComm( ea, form( 
    "  //  +0x%04X",deta ) );
               }
            }
          ea = NextNotTail( ea );
        }
    }


     用法如下:

    getasm(0x401000,0x4b40000x002027C60x00202846)

    其中,第一个参数和第二个参数是主程序 acplayer.exe 镜像的内存范围。后两个参数是 http 消息 id 的内存范围。
    但是没有找到结果。

    73DDEDBC  2A D2 DC 73 05 4B DA 73 F8 0D DC 73 7B 06 DC 73  *臆sK趕?躶{躶
    73DDEDCC  F8 0D DC 
    73 99 CC D8 73 71 D1 D8 73 35 D2 D8 73  ?躶櫶豷q沿s5邑s
    73DDEDDC  
    93 B1 D4 73 65 C4 D4 73 6C C9 D8 73 FD 3D DA 73  摫詓e脑sl韶s?
    73DDEDEC  
    87 39 DA 73 03 51 DA 73 CC 3D DA 73 4E 3A DA 73  ?趕Q趕?趕N:趕
    73DDEDFC  
    77 3B DA 73 6B FC DB 73 6B FC DB 73              w;趕ksks?





    766996DF    F3:A5           rep     movs dword ptr es:[edi], dword ptr [esi]             ; 内存断点

      F3   A5是汇编的原始二进制代码  
      rep   movs   dword   ptr   [edi],dword   ptr   [esi]是个串处理指令  
      是把esi所指向的内存中的内容复制到edi所指向的内存中  
      长度是在ecx寄存器中指定的

    t
    -IIS/6.0


    EAX 001E2AA0
    ECX 
    00000022
    EDX 
    00000089
    EBX 
    00204480
    ESP 000FFFEC
    EBP 0010032C
    ESI 002110A3 ASCII 
    49,"D:c10f085d0b4f4217a75e17ac2c97b89e82b4b96c1546468299b140a9d89ec88cad8fe51"
    EDI 0165B8A0
    EIP 766996DF WININET.766996DF
    0  ES 0023 32位 0(FFFFFFFF)
    1  CS 001B 32位 0(FFFFFFFF)
    0  SS 0023 32位 0(FFFFFFFF)
    0  DS 0023 32位 0(FFFFFFFF)
    0  FS 003B 32位 7FFDF000(FFF)
    0  GS 0000 NULL
    0
    0  LastErr ERROR_SUCCESS (00000000)
    EFL 
    00210206 (NO,NB,NE,A,NS,PE,GE,G)
    MM0 
    0000 0000 0000 0000
    MM1 00FF 00FF 00FF 00FF
    MM2 
    0000 0000 0000 0000
    MM3 
    0000 0000 0000 0000
    MM4 A5AC 15FF FFA4 F000
    MM5 A6AA AAAA AAAA A800
    MM6 A5A9 7B55 54FA 
    4000
    MM7 
    0000 0000 0000 0000


    73DA3CC0    FF15 14E1E073   call    dword ptr [73E0E114]                                 ; WININET.InternetReadFile


    0165B848                                3A 
    31 33 34 33 33            13433
    0165B858  
    32 30 63 30 62 64 31 34 61 66 33 31 34 34 30 36  20c0bd14af314406
    0165B868  
    36 63 35 64 37 31 33 34 39 39 34 34 63 36 63 31  6c5d71349944c6c1
    0165B878  
    63 37 63 33 31 62 61 34 65 34 61 30 35 35 30 37  c7c31ba4e4a05507
    0165B888  
    61 35 34 31 39 30 38 39 38 33 39 34 33 32 34 63  a54190898394324c
    0165B898  
    66 38 35 66 39 36 61 34 39 34 36 61 34 65 38 32  f85f96a4946a4e82
    0165B8A8  
    31 64 64 37 38 66 33 33 31 39 38 66 38 30 39 30  1dd78f33198f8090
    0165B8B8  
    32 66 34 64 32 65 61 34 66 64 61 62 31 61 63 61  2f4d2ea4fdab1aca
    0165B8C8  
    31 64 37 37 62 32 37 63 32 35 39 3B 49 4E 46 4F  1d77b27c259;INFO
    0165B8D8  3A                                               :

    EAX 
    00000089
    ECX 
    01651238 ASCII "ID:1343320c0bd14af3144066c5d71349944c6c1c7c31ba4e4a05507a54190898394324cf85f96a4946a4e821dd78f33198f80902f4d2ea4fdab1aca1d77b27c259;INFO:"
    EDX 
    01651239 ASCII "D:1343320c0bd14af3144066c5d71349944c6c1c7c31ba4e4a05507a54190898394324cf85f96a4946a4e821dd78f33198f80902f4d2ea4fdab1aca1d77b27c259;INFO:"
    EBX 001005B8
    ESP 001004B8
    EBP 001004C8
    ESI 016512B7 ASCII 
    "c259;INFO:"
    EDI 
    00000080
    EIP 73DA3D8B MFC42.73DA3D8B
    0  ES 0023 32位 0(FFFFFFFF)
    1  CS 001B 32位 0(FFFFFFFF)
    0  SS 0023 32位 0(FFFFFFFF)
    0  DS 0023 32位 0(FFFFFFFF)
    1  FS 003B 32位 7FFDF000(FFF)
    0  GS 0000 NULL
    0
    0  LastErr ERROR_SUCCESS (00000000)
    EFL 
    00200286 (NO,NB,NE,A,S,PE,L,LE)
    MM0 
    0000 0000 0000 0000
    MM1 00FF 00FF 00FF 00FF
    MM2 
    0000 0000 0000 0000
    MM3 
    0000 0000 0000 0000
    MM4 
    0000 0000 0000 0000
    MM5 
    8000 0000 0000 0000
    MM6 
    0000 0000 0000 0000
    MM7 
    0000 0000 0000 0000


    004461CE   .  E8 938B0300   call    
    <jmp.&MFC42.#4277_CString::Mid>


    001005BC  
    48 13 65 01 38 7F 65 01 D8 7F 65 01 00 16 D3 17  He8e?e.?
    001005CC  
    37 08 00 00 1C 52 47 00 78 B4 65 01 FF FF FF FF  7..RG.x磂
    001005DC  
    20 46 5C 00 02 00 00 00 28 11 65 01 D4 04 10 00   F\....(e?.
    001005EC  B0 0A 
    10 00 18 30 48 00 07 00 00 00 BC 0A 10 00  ?.0H....?.
    001005FC  
    85 57 44 00 2C AE 49 00 00 00 BC 00 F0 01 15 00  匴D.,甀...??.
    0010060C  
    48 B8 65 01 50 06 10 00 50 06 10 00 00 06 10 00  H竐P.P...
    0010061C  
    58 06 10 00 58 06 10 00 00 06 10 00 60 06 10 00  X.X...`.
    0010062C  
    60 06 10 00 00 06 10 00 70 23 10 00 38 B3 65 01  `...p#.8砮
    0010063C  
    88 04 00 00 50 B8 65 01 30 74 1F 00 01 00 00 00  ?..P竐0t....
    0010064C  
    50 B8 65 01 D4 86 E0 73 00 06 10 00 18 71 BC 00  P竐詥鄐..q?
    0010065C  
    00 06 10 00 88 7F 65 01 00 06 10 00 D8 06 10 02  ..?e..?
    0010066C  E8 F8 
    98 7C 00 00 BC 00 84 77 94 7C AC 06 10 00  桫榺..?剋攟?.
    0010067C  DF E5 
    98 7C 00 00 BC 00 00 00 00 00 70 B3 65 01  咤榺..?....p砮
    0010068C  
    00 00 BC 00 78 B3 65 01 A8 06 10 00 0C 07 10 00  ..?x砮?...


    00444F38   .  
    68 046A4400   push    00446A04
    00444F3D   .  E8 A2A10300   call    
    <jmp.&MFC42.#1105_AfxBeginThread>                    ;  解码完成。开始播放

    00444F38   .  
    68 046A4400   push    00446A04


    00446016   .  6A 01         push    1



     找到音频函数:

    00448939   .  55            push    ebp                                              ;  // 解码的关键函数。挂起此函数导致音频中断

    EBP ==>  >/0467FF80
    EBP+4    >|73DE0BBD  返回到 MFC42.73DE0BBD
    EBP+8    >|00100FB8
    EBP+C    >|0456FB30
    EBP+10   >|00B0C270
    EBP+14   >|00B0C5F0
    EBP+18   >|00B0C5F0
    EBP+1C   >|73E7764C  MFC42.73E7764C
    EBP+20   >|00000001
    EBP+24   >|00000000

  • 相关阅读:
    spring boot 在SpringMVC中使用Jackson并格式化时间
    MUI 同一个页面初始化多个pullrefresh 下拉刷新/上拉加载组件的问题
    Fixflow引擎解析(五)(内核)
    Fixflow引擎解析(四)(模型)
    Fixflow引擎解析(三)(模型)
    Fixflow引擎解析(二)(模型)
    Fixflow引擎解析(一)(介绍)
    Raspberry Pi 摄像头模块应用程序文档翻译
    js 继承如何让对象instanceof 当前类及父类均返回true?
    zabbix邮件脚本报警
  • 原文地址:https://www.cnblogs.com/diylab/p/1630179.html
Copyright © 2011-2022 走看看