在上一篇的跟踪中,调试后发现二次加密的密匙其实就是一个常量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, 40, 54);
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(0, 0x31) + 0x0A);
byte bMin = (byte) (ll401A60(0, 0x13) + 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 阅读(686)
评论(3) 编辑 收藏 所属分类:
反汇编