随笔 - 1  文章 - 37  trackbacks - 0
<2011年10月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

留言簿(16)

随笔分类

随笔档案

文章分类

文章档案

test

搜索

  •  

最新评论

在上一篇的跟踪中,调试后发现二次加密的密匙其实就是一个常量008B480C,分析一下整个二次加密的过程,以下代码均在VC6.0中运行通过,加密后数据与客户端实际发送数据一致。

函数1 - _declspec(naked) void _stdcall getEncryptMsg(long *nIdentity, char * dest)
nIdentity - 008B480C
dest - 二次加密明文
该函数负责生成二次加密后的明文,代码如下
注意:第13行是原来的代码,14行是自己加的,原因如下
在实际的客户端中,mov     al, byte ptr [eax]  取的是地址为008B480C的低8位,调试的时候该值为0,有可能二次解密后的解密掩码会存放在这里,目前还未可知;而在该代码中008B480C的地址是不可读的,因此这里需要将AL置0

static long nIdentity = 0x008B480C;

 1_declspec(naked) void _stdcall getEncryptMsg(long *nIdentity, char * dest){
 2    _asm{
 3          sub     esp, 8
 4  push    ebx
 5  push    ebp
 6  push    esi
 7  push    edi
 8  mov     edi, dword ptr [esp+0x20]  
 9  inc     edi                        
10  mov     dword ptr [esp+0x14], 4    
11L008:
12  mov     eax, dword ptr [esp+0x1C]  
13  ;mov     al, byte ptr [eax]         
14  xor     al, al
15  xor     al, 0x87                   
16  push    0x31    
17  push    0
18  mov     byte ptr [esp+0x1B], al    
19  call    ll401A60                   
20  add     al, 0x0A                   
21  push    0x13
22  push    0
23  mov     byte ptr [esp+0x30], al    
24  call    ll401A60                   
25
26  mov     cl, byte ptr [esp+0x30]    
27
28  mov     ebx, eax                   
29  add     bl, 0x0A                   
30  movzx   eax, bl                    
31  add     esp, 0x10                  
32  mov     byte ptr [edi-1], cl       
33  mov     byte ptr [edi+8], bl       
34  xor     esi, esi
35  lea     ebp, dword ptr [eax-1]     
36L029:
37  movzx   eax, byte ptr [esp+0x13]   
38  mov     edx, 0x80                  
39  mov     ecx, esi                   
40  sar     edx, cl                    
41  push    ebp
42  push    0
43  test    eax, edx                   
44  jnz L039
45  call    ll401A60
46  jmp L041
47L039:
48  call    ll401A60                   
49  add     al, bl                     
50L041:
51  add     al, byte ptr [esp+0x28]    
52  add     esp, 8
53  mov     byte ptr [edi+esi], al     
54  inc     esi                        
55  cmp     esi, 8                     
56  jl L029
57  mov     edx, dword ptr [esp+0x1C]  
58  mov     eax, dword ptr [esp+0x14]  
59  inc     edx                        
60  add     edi, 0x0A                  
61  dec     eax
62  mov     dword ptr [esp+0x1C], edx
63  mov     dword ptr [esp+0x14], eax
64  jnz L008
65  pop     edi
66  pop     esi
67  pop     ebp
68  pop     ebx
69  add     esp, 8
70  retn    8
71
72    }

73}

---------------------------------------------------------------------------------------------------------
函数2 - _declspec(naked) int _cdecl _ll401A60(int a1, int a2)
该函数负责生成一个伪随机数

_declspec(naked) int _cdecl _ll401A60(int a1, int a2)
{

    _asm
{
            push    esi
            push    edi
            call    ll4bb903
            mov     esi, eax
            call    ll4bb903
            sub     esi, eax
            jns L008
            neg     esi
L008:
            mov     ecx, dword ptr [esp
+0xC]  
            mov     edi, dword ptr [esp
+0x10
            mov     eax, esi                  
            sub     edi, ecx                  
            cdq                               
            inc     edi                       
            idiv    edi
            pop     edi
            pop     esi
            mov     eax, edx
            add     eax, ecx
            retn
    }

}

---------------------------------------------------------------------------------------------------------
函数3 - _declspec(naked) int _cdecl ll4bb903()
该函数根据客户端启动时生成的当前时间来进行随机数生成(这个步骤调试2个小时才出来)

long int_4D4F78 = 0x484953AE//客户端启动时的当前时间

_declspec(naked) 
int _cdecl ll4bb903()
{
    _asm
{
        mov     eax, dword ptr [int_4D4F78]
        imul    eax, eax, 
0x343FD
        add     eax, 
0x269EC3
        mov     dword ptr [int_4D4F78], eax
        xor     eax, eax
        mov     ax, word ptr [int_4D4F78
+2]
        and     eax, 
0x7FFF
        retn
    }

}


运行的Main函数如下,客户端在启动时执行了5次ll4bb903,因此这里也执行5次,不过服务器端也不可能知道客户端到底什么时候启动的,所以未必一定要执行5次,这点还没试
void encodeTest(){

    
//执行5次ll4bb903()
    ll4bb903();
    ll4bb903();
    ll4bb903();
    ll4bb903();
    ll4bb903();

    
long * ll = (long*)0x008b480c;
    ll 
= 0;

    
char dest[40];
    
    getEncryptMsg(
&nIdentity, dest);
    printf(
"%s\n", dest);

    
char idest[54];
    fnEncode6BitBuf(dest, idest, 
4054);
    printf(
"%s\n", idest);
}

以上代码转成JAVA代码如下:
public class DecodeMask {

    
private static int int_4D4F78 = 0x484953AE// 系统当前时间,不包含毫秒
    private static long nIdentity = 0x008B480C// 常量

    
private static int ll4bb903() {
        int_4D4F78 
= int_4D4F78 * 0x343FD + 0x269EC3;
        
int r = (int_4D4F78 >> 16& 0x7FFF;  //这里取高16位
        
return r;
    }


    
private static int ll401A60(int nFrom, int nTo) {
        
int nRandNum = 0;
        
int nRand = (ll4bb903() - ll4bb903());
        
if (nRand < 0)
            nRand 
= -nRand;
        nRandNum 
= nRand % (nTo - nFrom + 1+ nFrom;
        
return nRandNum;
    }


    
private static byte[] getEncryptMsg() {
        
byte[] dest = new byte[40];
        
int pos = 1;
        
for (int i = 0; i < 4; i++{

            
byte bMax = (byte) (ll401A60(00x31+ 0x0A);
            
byte bMin = (byte) (ll401A60(00x13+ 0x0A);

            dest[pos 
- 1= bMax;
            dest[pos 
+ 8= bMin;

            
for (int j = 0; j < 8; j++{
                
int bT = 0x80 >> j;
                
byte _b = (byte) ll401A60(0, bMin - 1);
                
if ((bT & 0x87!= 0{
                    _b 
+= bMin;
                }

                dest[pos 
+ j] = (byte) (_b + bMax);
            }

            nIdentity
++;
            pos 
+= 0x0a;
        }


        
return dest;
    }


    
/**
     * 调试: 客户端启动时的当前时间为 0x484953AE 
     * 选择角色进入游戏时,客户端向服务器端实际发送数据为 
     * #3<<<<<Jx?<<<<<<<<E`\cFo<mO@Q?A=ToC]\YE_DnGMDfQ_Q@IPIOMqLW?oPS?mD_E>dtAL!
     * 该方法运行后的正确输出应为: 
     * E`\cFo<mO@Q?A=ToC]\YE_DnGMDfQ_Q@IPIOMqLW?oPS?mD_E>dtAL
     
*/

    
public static void doTest() {
        
// 执行5次ll4bb903()
        ll4bb903();
        ll4bb903();
        ll4bb903();
        ll4bb903();
        ll4bb903();
        
byte[] b = getEncryptMsg();
        System.out.println(
"二次加密明文 - [" + new String(b) + "]");
        String s 
= PacketEncode.fnEncode6BitBuf(b);
        System.out.println(
"二次加密密文 - [" + s + "]");
    }


    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        doTest();
    }


}
posted on 2008-06-07 10:20 Phrancol Yang 阅读(670) 评论(3)  编辑  收藏 所属分类: 反汇编

FeedBack:
# re: [原]MIR3G二次加解密反汇编分析(四)——还原 2011-10-31 15:54 Mir3
ll4bb903 这其实是srand 函数  回复  更多评论
  
# re: [原]MIR3G二次加解密反汇编分析(四)——还原 2011-10-31 15:54 Mir3
int_4D4F78 是随即数种子  回复  更多评论
  
# re: [原]MIR3G二次加解密反汇编分析(四)——还原 2011-10-31 19:22 phrancol
@Mir3
好久没有研究这个...  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: