环境以及工具
Window7_x32
010 Editor v8.0.1_x32
OD
VS2017
第一步 找到判断注册结果的关键跳转和关键函数
使用OD打开010editor,进入到注册界面,先尝试输入随意的ID和Key,获取弹出的提示信息字符串
尝试在OD中搜索如下字符 “Invalid name or password.”,搜索结果如下
发现存在大量提示信息,我们在其中找到注册成功的提示信息,(上图红框:感谢购买010editor),双击查看反汇编窗口,见下图。
往上查看判断注册成功的关键跳转
我们发现地址为00DD5926处跳转JNZ 010Edito.00DD5A58应该为关键跳转,下方可以找到输出字符串”Password accepted. This ….”, 而其跳转地址处汇编代码为输出”Password accepted….”
(010editor使用QT界面库编写 ,我们可以猜测出push字符串随后的函数应为输出字符串)
回到关键跳转00DD5926处,判断密码为正确的条件为EDI = 0xDB,而EDI的值是EAX给的,而EAX为函数010Edito.00409C9B的返回值,这个函数可能为验证Key的关键函数,而我们动态调试发现有跳转直接跳转到cmp edi,0xdb。
同样为函数010Edito.00409C9B,现在可以认为这是关键函数,此时EDI的值为0x177,为了验证此跳转为关键跳转,我们把EDI的值修改为0xDB。
之后F9运行
验证成功!接下来我们进入函数分析。
第二步 分析关键函数1(返回DB为注册成功)
函数010Edito.00409C9B,参数情况为:
arg1 = 0x9 ;
arg2 = 0x4389;
从下往上看,找到需要的0xDB,而跳转条件是eax = 0x2D, 为函数010Edito.0040A826的返回值。
第三步 分析关键函数2(返回2D为注册成功)
进入函数,该函数作用为将key取出,放在在局部变量数组中,数组起始地址为ebx-24
key[0 ] = [ebx-24]=0x12 key[1 ] = [ebx-23]=0x34 key[2 ] = [ebx-22]=0x56 key[3 ] = [ebx-21]=0x78 key[4 ] = [ebx-20]=0x90 key[5 ] = [ebx-1F]=0x12 key[6 ] = [ebx-1E]=0x34 key[7 ] = [ebx-1D]=0x56 key[8 ] = [ebx-1C]=0x78 key[9 ] = [ebx-1B]=0x90
密钥数组对应如上,该处汇编代码如下,当KEY[3] == 0x9C时
013BDC5D . 8A5D DF MOV BL,BYTE PTR SS:[EBP-0x21] ; key[3] 013BDC60 . 8A7D E1 MOV BH,BYTE PTR SS:[EBP-0x1F] ; key[5] 013BDC63 . 80FB 9C CMP BL,0x9C ; 是否等于0x9c 013BDC66 . 75 70 JNZ SHORT 010Edito.013BDCD8 ; 跳转到是否等于FC 013BDC68 . 8A45 DC MOV AL,BYTE PTR SS:[EBP-0x24] ; key[0] 013BDC6B . 3245 E2 XOR AL,BYTE PTR SS:[EBP-0x1E] ; key[0]^key[6] 013BDC6E . 8845 E8 MOV BYTE PTR SS:[EBP-0x18],AL ; 013BDC71 . 8A45 DD MOV AL,BYTE PTR SS:[EBP-0x23] ; key[1] 013BDC74 . 3245 E3 XOR AL,BYTE PTR SS:[EBP-0x1D] ; key[1]^key[7] 013BDC77 . FF75 E8 PUSH DWORD PTR SS:[EBP-0x18] 013BDC7A . 0FB6C8 MOVZX ECX,AL 013BDC7D . B8 00010000 MOV EAX,0x100 013BDC82 . 66:0FAFC8 IMUL CX,AX ; (key[1]^key[7])*0x100 013BDC86 . 8A45 DE MOV AL,BYTE PTR SS:[EBP-0x22] ; key[2] 013BDC89 . 32C7 XOR AL,BH ; key[2]^key[5] 013BDC8B . 0FB6C0 MOVZX EAX,AL 013BDC8E . 66:03C8 ADD CX,AX ;cx = (key[1]^key[7])*0x100 + key[2]^key[5] 013BDC91 . 0FB7F1 MOVZX ESI,CX 013BDC94 . E8 AB9904FF CALL 010Edito.00407644 013BD0B0 /> \55 PUSH EBP 013BD0B1 |. 8BEC MOV EBP,ESP 013BD0B3 |. 8B45 08 MOV EAX,[ARG.1] ; eax = key[0]^key[6] 013BD0B6 |. 34 18 XOR AL,0x18 ; al = key[0]^key[6]^0x18 013BD0B8 |. 04 3D ADD AL,0x3D ; al = key[0]^key[6]^0x18 + 0x3D 013BD0BA |. 34 A7 XOR AL,0xA7 ; al =(key[0]^key[6]^0x18+0x3D)^0xA7 013BD0BC |. 5D POP EBP 013BD0BD \. C3 RETN 013BDC99 . 0FB6C0 MOVZX EAX,AL 013BDC9C . 56 PUSH ESI ; esi = (key[1]^key[7])*0x100 + key[2]^key[5] 013BDC9D . 8947 1C MOV DWORD PTR DS:[EDI+0x1C],EAX 013BDCA0 . E8 23A704FF CALL 010Edito.004083C8 013BD020 /> \55 PUSH EBP 013BD021 |. 8BEC MOV EBP,ESP 013BD023 |. 8B45 08 MOV EAX,[ARG.1] ;eax=(key[1]^key[7])*100+key[2]^key[5] 013BD026 |. B9 0B000000 MOV ECX,0xB ; ecx = 0xB 013BD02B |. 35 92780000 XOR EAX,0x7892 ;eax=((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 013BD030 |. 05 304D0000 ADD EAX,0x4D30 ;eax=((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30 013BD035 |. 35 21340000 XOR EAX,0x3421 ;eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421 013BD03A |. 0FB7C0 MOVZX EAX,AX 013BD03D |. 99 CDQ 013BD03E |. F7F9 IDIV ECX ;eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB 013BD040 |. 85D2 TEST EDX,EDX ;eax/ecx的余数是否为0 013BD042 |. 74 02 JE SHORT 010Edito.013BD046 ;如果余数不为0,清零eax 013BD044 |. 33C0 XOR EAX,EAX 013BD046 |> 5D POP EBP 013BD047 \. C3 RETN 013BDCA5 . 8B4F 1C MOV ECX,DWORD PTR DS:[EDI+0x1C] ; ecx = (key[0]^key[6]^0x18+0x3D)^0xA7 013BDCA8 . 83C4 08 ADD ESP,0x8 013BDCAB . 0FB7C0 MOVZX EAX,AX ;eax=(((key[1]^key[7])*100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421 013BDCAE . 8947 20 MOV DWORD PTR DS:[EDI+0x20],EAX ;[EDI+0x20] =(((key[1]^key[7])*100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB 013BDCB1 . 85C9 TEST ECX,ECX 013BDCB3 . 0F84 BC010000 JE 010Edito.013BDE75 ;ecx = 0 则eax=E7返回,验证失败 013BDCB9 . 85C0 TEST EAX,EAX 013BDCBB . 0F84 B4010000 JE 010Edito.013BDE75 ;eax = 0 则eax=E7返回,验证失败 013BDCC1 . 3D E8030000 CMP EAX,0x3E8 013BDCC6 . 0F87 A9010000 JA 010Edito.013BDE75 ;eax > 0x3E8 则eax=E7返回,验证失败 013BDCCC . 83F9 02 CMP ECX,0x2 ;ecx小于等于1时,借位cf=1,否则cf=0 013BDCCF . 1BF6 SBB ESI,ESI ; esi=esi-esi-CF=-cf 013BDCD1 . 23F1 AND ESI,ECX ;esi = esi & ecx 013BDCD3 . E9 B3000000 JMP 010Edito.013BDD8B ;0xAC分支也跳转到这里013BDD8B
当KEY[3] == 0x9C时,等换成C为
case 0x9C: { [EDI+0x1C] = (key[0]^key[6]^0x18+0x3D)^0xA7; //最后一步验证用到 [EDI+0x20] =(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421; eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421; ecx = (key[0]^key[6]^0x18+0x3D)^0xA7; cf = 0; if(eax % 0xB != 0) { eax = 0; } if(ecx == 0 || eax == 0 || eax > 0x3E8) { //验证失败 return; } else { eax=(((key[1]^key[7])*0x100+key[2]^key[5])^0x7892 + 0x4D30)^0x3421/0xB; [EDI+0x20] = eax; if(ecx <= 1) { cf = 1; } esi = (0 - cf) & ecx; //cf=0 则 esi=0; } break; }
当KEY[3] == 0xFC时,所有跳转最终都不返回我们需要的0x2D ,跳过。
当KEY[3] == 0xAC时
013BDCFC > \80FB AC CMP BL,0xAC 013BDCFF . 0F85 70010000 JNZ 010Edito.013BDE75 013BDD05 . 8A45 DD MOV AL,BYTE PTR SS:[EBP-0x23] ; al = key[1] 013BDD08 . 3245 E3 XOR AL,BYTE PTR SS:[EBP-0x1D] ; al = key[1]^key[7] 013BDD0B . 0FB6C8 MOVZX ECX,AL ; ecx = key[1]^key[7] 013BDD0E . B8 00010000 MOV EAX,0x100 013BDD13 . 66:0FAFC8 IMUL CX,AX ; cx = (key[1]^key[7]) * 0x100 013BDD17 . 8A45 DE MOV AL,BYTE PTR SS:[EBP-0x22] ; al = key[2] 013BDD1A . 32C7 XOR AL,BH ; al = key[2]^key[5] 013BDD1C . C747 1C 02000>MOV DWORD PTR DS:[EDI+0x1C],0x2 ;[edi+0x1C] = 0x2 013BDD23 . 0FB6C0 MOVZX EAX,AL ; eax = key[2]^key[5] 013BDD26 . 66:03C8 ADD CX,AX ; cx = (key[1]^key[7]) * 0x100 + key[2]^key[5] 013BDD29 . 0FB7C1 MOVZX EAX,CX ; eax = (key[1]^key[7]) * 0x100 + key[2]^key[5] 013BDD2C . 50 PUSH EAX 013BDD2D . E8 96A604FF CALL 010Edito.004083C8 013BD020 /> \55 PUSH EBP 013BD021 |. 8BEC MOV EBP,ESP 013BD023 |. 8B45 08 MOV EAX,[ARG.1] 013BD026 |. B9 0B000000 MOV ECX,0xB 013BD02B |. 35 92780000 XOR EAX,0x7892 ; eax = ((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 013BD030 |. 05 304D0000 ADD EAX,0x4D30 ; eax = ((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30 013BD035 |. 35 21340000 XOR EAX,0x3421 ; eax = (((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421 013BD03A |. 0FB7C0 MOVZX EAX,AX 013BD03D |. 99 CDQ 013BD03E |. F7F9 IDIV ECX ; eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB 013BD040 |. 85D2 TEST EDX,EDX ; 余数edx != 0 则,eax=0 013BD042 |. 74 02 JE SHORT 010Edito.013BD046 013BD044 |. 33C0 XOR EAX,EAX 013BD046 |> 5D POP EBP 013BD047 \. C3 RETN 013BDD32 . 0FB7C0 MOVZX EAX,AX 013BDD35 . 83C4 04 ADD ESP,0x4 013BDD38 . 8947 20 MOV DWORD PTR DS:[EDI+0x20],EAX 013BDD3B . 85C0 TEST EAX,EAX ; 检测上面的函数返回结果eax是否为0 013BDD3D . 0F84 32010000 JE 010Edito.013BDE75;eax=0跳转到返回0xE7,验证失败 013BDD43 . 3D E8030000 CMP EAX,0x3E8 013BDD48 . 0F87 27010000 JA 010Edito.013BDE75;eax大于0x3E8跳转到返回0xE7,验证失败 013BDD4E . 0FB655 E5 MOVZX EDX,BYTE PTR SS:[EBP-0x1B] ; edx = key[9] 013BDD52 . 0FB64D E0 MOVZX ECX,BYTE PTR SS:[EBP-0x20] ; ecx = key[4] 013BDD56 . 0FB6C7 MOVZX EAX,BH ; eax = key[5] 013BDD59 . 33D0 XOR EDX,EAX ; edx = key[9]^key[5] 013BDD5B . 0FB645 E4 MOVZX EAX,BYTE PTR SS:[EBP-0x1C] ; eax = key[8] 013BDD5F . 33C8 XOR ECX,EAX ; ecx = key[4]^key[8] 013BDD61 . C1E2 08 SHL EDX,0x8 013BDD64 . 0FB645 E2 MOVZX EAX,BYTE PTR SS:[EBP-0x1E] ; eax = key[6] 013BDD68 . 03D1 ADD EDX,ECX ; edx = ((key[9]^key[5])<<8) + key[4]^key[8] 013BDD6A . 0FB64D DC MOVZX ECX,BYTE PTR SS:[EBP-0x24] ; ecx = key[0] 013BDD6E . C1E2 08 SHL EDX,0x8 ; edx = (((key[9]^key[5]) << 8) + key[4]^key[8]) << 8 013BDD71 . 33C8 XOR ECX,EAX ; ecx = key[0]^key[6] 013BDD73 . 03D1 ADD EDX,ECX ; edx = ((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6] 013BDD75 . 68 278C5B00 PUSH 010Edito.005B8C27 ; CCCCCCCC 013BDD7A . 52 PUSH EDX 013BDD7B . E8 0BCA04FF CALL 010Edito.0040A78B 013BCF90 /> \55 PUSH EBP 013BCF91 |. 8BEC MOV EBP,ESP 013BCF93 |. 8B4D 08 MOV ECX,[ARG.1] ; ecx = ((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6] 013BCF96 |. B8 F1F0F0F0 MOV EAX,0xF0F0F0F1 013BCF9B |. 334D 0C XOR ECX,[ARG.2] ; ecx = (((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27 013BCF9E |. 81F1 78C02200 XOR ECX,0x22C078 ; ecx = ((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 013BCFA4 |. 81E9 75C10200 SUB ECX,0x2C175 ; ecx = ((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175 013BCFAA |. 81F1 6731E5FF XOR ECX,0xFFE53167 ; ecx = (((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167 013BCFB0 |. 81E1 FFFFFF00 AND ECX,0xFFFFFF ; ecx = ((((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167) & 0xFFFFFF 013BCFB6 |. F7E1 MUL ECX ; eax = 0xF0F0F0F1 * ecx 结果高32位放在edx。 低32位放在eax 013BCFB8 |. C1EA 04 SHR EDX,0x4 013BCFBB |. 8BC2 MOV EAX,EDX 013BCFBD |. C1E0 04 SHL EAX,0x4 013BCFC0 |. 03C2 ADD EAX,EDX 013BCFC2 |. 2BC8 SUB ECX,EAX ;结果为0 则 zf=1 013BCFC4 |. B8 00000000 MOV EAX,0x0 013BCFC9 |. 0F44C2 CMOVE EAX,EDX ;当zf = 1时移动 013BCFCC |. 5D POP EBP 013BCFCD \. C3 RETN 013BDD80 . 83C4 08 ADD ESP,0x8 013BDD83 . 8945 F0 MOV DWORD PTR SS:[EBP-0x10],EAX 013BDD86 . 8947 34 MOV DWORD PTR DS:[EDI+0x34],EAX 013BDD89 . 8BF0 MOV ESI,EAX 013BDD8B > \8D45 EC LEA EAX,DWORD PTR SS:[EBP-0x14];0x9C分支也跳转到这里
转换成C代码
case 0xAC: { eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421); ecx = ((((((((key[9]^key[5]) << 8) + key[4]^key[8]) << 8) + key[0]^key[6]) ^ 0x005B8C27) ^ 0x22C078 - 0x2C175) ^ 0xFFE53167) & 0xFFFFFF; if(eax % 0xB != 0) { eax = 0; return ; //跳转返回0x7E分支,验证失败 } eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB; eax = 0xF0F0F0F1 * ecx; // 结果高32位放在edx。 低32位放在eax edx = edx >> 4; eax = edx; eax = eax << 4; eax = eax + edx; ecx = ecx - eax; eax = 0; if(ecx==0) { eax = edx; } [ebp-0x10] = eax; //最后一步验证用到 [edi+0x34] = eax; esi = eax; break; }
分支0x9C、0xAC都将运行到此处
013BDD8B > \8D45 EC LEA EAX,DWORD PTR SS:[EBP-0x14] 013BDD8E . 50 PUSH EAX 013BDD8F . 8D4F 04 LEA ECX,DWORD PTR DS:[EDI+0x4] 013BDD92 . FF15 782BE702 CALL DWORD PTR DS:[<&Qt5Core.?toUtf8@QString@@QBE?AVQByteArr>; Qt5Core.?toUtf8@QString@@QBE?AVQByteArray@@XZ
不知道这段是干嘛,我们继续单步,到如上图所示,函数[<&Qt5Core.?data@QByteArray@@QAE>] 返回了用户名字符串,然后传入函数010Edito.00402E50,其再返回 一串类似哈希值的值,那么这个函数的作用应该为处理函数名称,进入分析。
第四步 分析用户名处理函数
根据mov esp, 0x10可知,用户名处理函数共有四个参数
参数1:用户名
参数2:当BL=0XFC时为1,否则为0,根据前面的分析可知,BL为Key[3]
参数3:esi,经上一个函数处理得到
参数4:[edi+0x20],经上一个函数处理得到
013BD120 /> \55 PUSH EBP 013BD121 |. 8BEC MOV EBP,ESP 013BD123 |. 83EC 10 SUB ESP,0x10 013BD126 |. 8B55 08 MOV EDX,[ARG.1] ;edx = 用户名pName 013BD129 |. 33C9 XOR ECX,ECX ;ecx = 0 013BD12B |. 56 PUSH ESI ;备份esi 013BD12C |. 8BF2 MOV ESI,EDX ;esi = 用户名pName 013BD12E |. 894D FC MOV [LOCAL.1],ECX ;[LOCAL.1] = 0 013BD131 |. 57 PUSH EDI ;备份EDI 013BD132 |. 8D7E 01 LEA EDI,DWORD PTR DS:[ESI+0x1] ;edi = 用户名地址 + 1,后面被esi减去求得长度 013BD135 |> 8A06 /MOV AL,BYTE PTR DS:[ESI] ;al = pName[0] 013BD137 |. 46 |INC ESI ;pName++ 013BD138 |. 84C0 |TEST AL,AL 013BD13A |.^ 75 F9 \JNZ SHORT 010Edito.013BD135 ;判断是否到达字符串结尾 013BD13C |. 2BF7 SUB ESI,EDI ;求得长度,ESI指向为用户名字符串结尾的'\0' 013BD13E |. 33FF XOR EDI,EDI 013BD140 |. 85F6 TEST ESI,ESI 013BD142 |. 0F8E F0000000 JLE 010Edito.013BD238 ;检查长度是否不为0 013BD148 |. 53 PUSH EBX 013BD149 |. 8B5D 14 MOV EBX,[ARG.4] ;ebx = [ARG.4] = 传入的[edi+0x20] 013BD14C |. 894D F0 MOV [LOCAL.4],ECX ;置零 013BD14F |. 894D F4 MOV [LOCAL.3],ECX ;置零 013BD152 |. 8B4D 10 MOV ECX,[ARG.3] ;ecx = [ARG.3] = 传入的esi 013BD155 |. C1E3 04 SHL EBX,0x4 013BD158 |. 2B5D 14 SUB EBX,[ARG.4] ;ebx = ([ARG.4] *16) - [ARG.4] 013BD15B |. C1E1 04 SHL ECX,0x4 013BD15E |. 034D 10 ADD ECX,[ARG.3] ;ecx = ([ARG.3] *16) + [ARG.3] 013BD161 |. 894D F8 MOV [LOCAL.2],ECX ;[LOCAL.2] = ([ARG.3] << 4) + [ARG.3] 013BD164 |> 0FB60417 /MOVZX EAX,BYTE PTR DS:[EDI+EDX] 013BD168 |. 50 |PUSH EAX ; /c = B6 013BD169 |. FF15 9422E702 |CALL DWORD PTR DS:[<&MSVCR120.toupper>] ; \toupper 小写字母转换为大写字母 013BD16F |. 8BD0 |MOV EDX,EAX ;返回值复制给edx,大写字符 013BD171 |. 83C4 04 |ADD ESP,0x4 013BD174 |. 8B0C95 4841E6>|MOV ECX,DWORD PTR DS:[EDX*4+0x2E64148] ;将大写字母作为索引从数组0x2E64148中取内容 ;为了方便,把数组0x2E64148称为nArray,故这里ecx = nArray[edx] 013BD17B |. 034D FC |ADD ECX,[LOCAL.1] ;ecx =nArray[大写字符] + [LOCAL.1] ,[LOCAL.1]最初为0 013BD17E |. 837D 0C 00 |CMP [ARG.2],0x0 ;判断是哪种类型的注册 013BD182 |. 74 4A |JE SHORT 010Edito.013BD1CE ;注册类型1--------------------------------------------------------- 013BD184 |. 8D42 0D |LEA EAX,DWORD PTR DS:[EDX+0xD] 013BD187 |. 25 FF000000 |AND EAX,0xFF ;eax = [大写字符+0xD] & 0xFF,这个值为数组下标,与0xFF可能说明数组最大个数为0xFF,即256个 013BD18C |. 330C85 4841E6>|XOR ECX,DWORD PTR DS:[EAX*4+0x2E64148] ;ecx = (nArray[大写字符] + [LOCAL.1]) ^ nArray[eax] 013BD193 |. 8D42 2F |LEA EAX,DWORD PTR DS:[EDX+0x2F] ;eax = [大写字符+0x2F] 013BD196 |. 25 FF000000 |AND EAX,0xFF ;eax = eax & 0xFF 013BD19B |. 0FAF0C85 4841>|IMUL ECX,DWORD PTR DS:[EAX*4+0x2E64148] ;ecx = ecx*nArray[eax] 013BD1A3 |. 8B45 F8 |MOV EAX,[LOCAL.2] ; 010Edito.01885E59 ;eax = [LOCAL.2] = ([ARG.3] << 4) + [ARG.3] 013BD1A6 |. 0FB6C0 |MOVZX EAX,AL ;eax &= 0xFF 013BD1A9 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] ;ecx = ecx + nArray[eax] 013BD1B0 |. 0FB6C3 |MOVZX EAX,BL ;eax = ebx = ([ARG.4] << 4) - [ARG.4] 013BD1B3 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] ;ecx = ecx + nArray[eax] 013BD1BA |. 8B45 F4 |MOV EAX,[LOCAL.3] ;eax = [LOCAL.3] 013BD1BD |. 0FB6C0 |MOVZX EAX,AL 013BD1C0 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] ;ecx = ecx + nArray[eax] 013BD1C7 |. 8BC1 |MOV EAX,ECX ;eax = ecx 013BD1C9 |. 8945 FC |MOV [LOCAL.1],EAX ;[LOCAL.1] = eax 013BD1CC |. EB 48 |JMP SHORT 010Edito.013BD216 ;注册类型0---------------------------------------------------------- 013BD1CE |> 8D42 3F |LEA EAX,DWORD PTR DS:[EDX+0x3F];这里不同 013BD1D1 |. 25 FF000000 |AND EAX,0xFF 013BD1D6 |. 330C85 4841E6>|XOR ECX,DWORD PTR DS:[EAX*4+0x2E64148] 013BD1DD |. 8D42 17 |LEA EAX,DWORD PTR DS:[EDX+0x17];这里不同 013BD1E0 |. 25 FF000000 |AND EAX,0xFF 013BD1E5 |. 0FAF0C85 4841>|IMUL ECX,DWORD PTR DS:[EAX*4+0x2E64148] 013BD1ED |. 8B45 F8 |MOV EAX,[LOCAL.2] ; 010Edito.01885E59 013BD1F0 |. 0FB6C0 |MOVZX EAX,AL 013BD1F3 |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] 013BD1FA |. 0FB6C3 |MOVZX EAX,BL 013BD1FD |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] 013BD204 |. 8B45 F0 |MOV EAX,[LOCAL.4] ;eax = [LOCAL.4], 另一种注册类型这里为 [LOCAL.3] 013BD207 |. 0FB6C0 |MOVZX EAX,AL 013BD20A |. 030C85 4841E6>|ADD ECX,DWORD PTR DS:[EAX*4+0x2E64148] 013BD211 |. 8BC1 |MOV EAX,ECX 013BD213 |. 894D FC |MOV [LOCAL.1],ECX ;共通线---------------------------------------------------------------- 013BD216 |> 8345 F4 13 |ADD [LOCAL.3],0x13 ;[LOCAL.3] += 0x13 013BD21A |. 47 |INC EDI 013BD21B |. 8345 F8 09 |ADD [LOCAL.2],0x9 ;[LOCAL.2] += 0x9 013BD21F |. 83C3 0D |ADD EBX,0xD ;EBX += 0xD 013BD222 |. 8345 F0 07 |ADD [LOCAL.4],0x7 ;[LOCAL.4] += 0x7 013BD226 |. 8B55 08 |MOV EDX,[ARG.1] ; EDX = [ARG.1] = 用户名 013BD229 |. 3BFE |CMP EDI,ESI ;ESI指向为用户名字符串结尾的0, 判断EDI是否也到结尾,没有则继续循环计算 013BD22B |.^ 0F8C 33FFFFFF \JL 010Edito.013BD164 013BD231 |. 5B POP EBX ; 05661E08 013BD232 |. 5F POP EDI ; 05661E08 013BD233 |. 5E POP ESI ; 05661E08 013BD234 |. 8BE5 MOV ESP,EBP 013BD236 |. 5D POP EBP ; 05661E08 013BD237 |. C3 RETN ;用户名长度为0------------------------------------------------------ 013BD238 |> 5F POP EDI ; 05661E08 013BD239 |. 8BC1 MOV EAX,ECX 013BD23B |. 5E POP ESI ; 05661E08 013BD23C |. 8BE5 MOV ESP,EBP 013BD23E |. 5D POP EBP ; 05661E08 013BD23F \. C3 RETN
转换成C语言
arg_1 = pName; arg_2; arg_3 = ESI; arg_4 = [edi+0x20]; DWORD LOCAL_1 = 0; DWORD LOCAL_2 = (arg_3 * 16) + arg_3 DWORD LOCAL_3 = 0; DWORD LOCAL_4 = 0; ebx =(arg_4 * 16) - arg_4; char nArray[256]= { 39CB44B8, 23754F67, 5F017211, 3EBB24DA, 351707C6, 63F9774B, 17827288, 0FE74821, 5B5F670F, 48315AE8, 785B7769, 2B7A1547, 38D11292, 42A11B32, 35332244, 77437B60, 1EAB3B10, 53810000, 1D0212AE, 6F0377A8, 43C03092, 2D3C0A8E, 62950CBF, 30F06FFA, 34F710E0, 28F417FB, 350D2F95, 5A361D5A, 15CC060B, 0AFD13CC, 28603BCF, 3371066B, 30CD14E4, 175D3A67, 6DD66A13, 2D3409F9, 581E7B82, 76526B99, 5C8D5188, 2C857971, 15F51FC0, 68CC0D11, 49F55E5C, 275E4364, 2D1E0DBC, 4CEE7CE3, 32555840, 112E2E08, 6978065A, 72921406, 314578E7, 175621B7, 40771DBF, 3FC238D6, 4A31128A, 2DAD036E, 41A069D6, 25400192, 00DD4667, 6AFC1F4F, 571040CE, 62FE66DF, 41DB4B3E, 3582231F, 55F6079A, 1CA70644, 1B1643D2, 3F7228C9, 5F141070, 3E1474AB, 444B256E, 537050D9, 0F42094B, 2FD820E6, 778B2E5E, 71176D02, 7FEA7A69, 5BB54628, 19BA6C71, 39763A99, 178D54CD, 01246E88, 3313537E, 2B8E2D17, 2A3D10BE, 59D10582, 37A163DB, 30D6489A, 6A215C46, 0E1C7A76, 1FC760E7, 79B80C65, 27F459B4, 799A7326, 50BA1782, 2A116D5C, 63866E1B, 3F920E3C, 55023490, 55B56089, 2C391FD1, 2F8035C2, 64FD2B7A, 4CE8759A, 518504F0, 799501A8, 3F5B2CAD, 38E60160, 637641D8, 33352A42, 51A22C19, 085C5851, 032917AB, 2B770AC7, 30AC77B3, 2BEC1907, 035202D0, 0FA933D3, 61255DF3, 22AD06BF, 58B86971, 5FCA0DE5, 700D6456, 56A973DB, 5AB759FD, 330E0BE2, 5B3C0DDD, 495D3C60, 53BD59A6, 4C5E6D91, 49D9318D, 103D5079, 61CE42E3, 7ED5121D, 14E160ED, 212D4EF2, 270133F0, 62435A96, 1FA75E8B, 6F092FBE, 4A000D49, 57AE1C70, 004E2477, 561E7E72, 468C0033, 5DCC2402, 78507AC6, 58AF24C7, 0DF62D34, 358A4708, 3CFB1E11, 2B71451C, 77A75295, 56890721, 0FEF75F3, 120F24F1, 01990AE7, 339C4452, 27A15B8E, 0BA7276D, 60DC1B7B, 4F4B7F82, 67DB7007, 4F4A57D9, 621252E8, 20532CFC, 6A390306, 18800423, 19F3778A, 462316F0, 56AE0937, 43C2675C, 65CA45FD, 0D604FF2, 0BFD22CB, 3AFE643B, 3BF67FA6, 44623579, 184031F8, 32174F97, 4C6A092A, 5FB50261, 01650174, 33634AF1, 712D18F4, 6E997169, 5DAB7AFE, 7C2B2EE8, 6EDB75B4, 5F836FB6, 3C2A6DD6, 292D05C2, 052244DB, 149A5F4F, 5D486540, 331D15EA, 4F456920, 483A699F, 3B450F05, 3B207C6C, 749D70FE, 417461F6, 62B031F1, 2750577B, 29131533, 588C3808, 1AEF3456, 0F3C00EC, 7DA74742, 4B797A6C, 5EBB3287, 786558B8, 00ED4FF2, 6269691E, 24A2255F, 62C11F7E, 2F8A7DCD, 643B17FE, 778318B8, 253B60FE, 34BB63A3, 5B03214F, 5F1571F4, 1A316E9F, 7ACF2704, 28896838, 18614677, 1BF569EB, 0BA85EC9, 6ACA6B46, 1E43422A, 514D5F0E, 413E018C, 307626E9, 01ED1DFA, 49F46F5A, 461B642B, 7D7007F2, 13652657, 6B160BC5, 65E04849, 1F526E1C, 5A0251B6, 2BD73F69, 2DBF7ACD, 51E63E80, 5CF2670F, 21CD0A03, 5CFF0261, 33AE061E, 3BB6345F, 5D814A75, 257B5DF4, 0A5C2C5B, 16A45527, 16F23945 }; while(nNameLen) { pName[i] char cName = toupper(pName); //小写转大写 //注册类型1 if(key[3] != 0xFC) { LOCAL_1 = (nArray[cName]+LOCAL_1); LOCAL_1 ^= nArray[(cName+0xD)]; LOCAL_1 *= nArray[(cName+0x2F)]; LOCAL_1 += nArray[LOCAL_2]; LOCAL_1 += nArray[ebx]; LOCAL_1 += nArray[LOCAL_3]; } //注册类型0,没有用到 else if(key[3] == 0xFC) { LOCAL_1 = (nArray[cName]+LOCAL_1); LOCAL_1 ^= nArray[(cName+0x3F)]; LOCAL_1 *= nArray[(cName+0x17)]; LOCAL_1 += nArray[LOCAL_2]; LOCAL_1 += nArray[ebx]; LOCAL_1 += nArray[LOCAL_4]; } LOCAL_3 += 0x13; nNameLen--; LOCAL_2 += 0x9; ebx += 0xD LOCAL_4 += 0x7; i++; } return LOCAL_1;
函数返回结果如上图。
第五步 处理计算结果
由上图分析可知,接下来将处理用户名函数的返回值多次右移比较,根据结果分发返回值,最终跳转到我们需要的返回值0x2D。代码如下
013BDDB6 . E8 955004FF CALL 010Edito.00402E50 ; 处理用户名的函数 013BDDBB . 8BD0 MOV EDX,EAX 013BDDBD . 83C4 10 ADD ESP,0x10 ; 意味着上面函数有四个参数 013BDDC0 . 3855 E0 CMP BYTE PTR SS:[EBP-0x20],DL ; 比较key[4],返回值低8位 013BDDC3 . 0F85 81000000 JNZ 010Edito.013BDE4A ; 跳转到返回0xE7,失败 013BDDC9 . 8BCA MOV ECX,EDX 013BDDCB . C1E9 08 SHR ECX,0x8 ; 右移0x8 013BDDCE . 3AF9 CMP BH,CL ; key[5],cl 013BDDD0 . 75 78 JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败 013BDDD2 . 8BCA MOV ECX,EDX 013BDDD4 . C1E9 10 SHR ECX,0x10 ; 右移10位 013BDDD7 . 384D E2 CMP BYTE PTR SS:[EBP-0x1E],CL ; key[6] 013BDDDA . 75 6E JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败 013BDDDC . C1E8 18 SHR EAX,0x18 ; 右移0x18 013BDDDF . 3845 E3 CMP BYTE PTR SS:[EBP-0x1D],AL ; key[7] 013BDDE2 . 75 66 JNZ SHORT 010Edito.013BDE4A ; 跳转到返回0xE7,失败 013BDDE4 . 80FB 9C CMP BL,0x9C ; Switch (cases 9C..FC) 013BDDE7 . 75 0F JNZ SHORT 010Edito.013BDDF8 013BDDE9 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+0x8] ; Case 9C of switch 013BDDE4 013BDDEC . 3B47 1C CMP EAX,DWORD PTR DS:[EDI+0x1C] ; 小于等于 013BDDEF . 76 52 JBE SHORT 010Edito.013BDE43 ; 跳转到返回0x2D,验证正确 013BDDF1 . BE 4E000000 MOV ESI,0x4E 013BDDF6 . EB 57 JMP SHORT 010Edito.013BDE4F ; 返回返回4E,验证失败 013BDDF8 > 80FB FC CMP BL,0xFC 013BDDFB . 75 2E JNZ SHORT 010Edito.013BDE2B ; FC分支得不到正确结果,跳过
013BDE2B > 80FB AC CMP BL,0xAC 013BDE2E . 75 1A JNZ SHORT 010Edito.013BDE4A 013BDE30 . 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-0x10] ; Case AC of switch 013BDDE4 013BDE33 . 85C0 TEST EAX,EAX 013BDE35 . 74 13 JE SHORT 010Edito.013BDE4A ; 跳转到验证错误 013BDE37 . 3945 0C CMP DWORD PTR SS:[EBP+0xC],EAX 013BDE3A . 76 07 JBE SHORT 010Edito.013BDE43 ; 跳转到返回0x2D,验证正确 013BDE3C . BE 4E000000 MOV ESI,0x4E 013BDE41 . EB 0C JMP SHORT 010Edito.013BDE4F 013BDE43 > BE 2D000000 MOV ESI,0x2D ; 验证正确,返回0x2D!!!! 013BDE48 . EB 05 JMP SHORT 010Edito.013BDE4F 013BDE4A > BE E7000000 MOV ESI,0xE7 ; Default case of switch 013BDDE4 013BDE4F > 8D4D EC LEA ECX,DWORD PTR SS:[EBP-0x14] 013BDE52 . C745 FC FFFFF>MOV DWORD PTR SS:[EBP-0x4],-0x1 013BDE59 . FF15 7C24E702 CALL DWORD PTR DS:[<&Qt5Core.??1Q>; Qt5Core.??1QByteArray@@QAE@XZ 013BDE5F . 8BC6 MOV EAX,ESI 013BDE61 . 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-0xC] 013BDE64 . 64:890D 00000>MOV DWORD PTR FS:[0],ECX 013BDE6B . 59 POP ECX ; 0584FD48 013BDE6C . 5F POP EDI ; 0584FD48 013BDE6D . 5E POP ESI ; 0584FD48 013BDE6E . 5B POP EBX ; 0584FD48 013BDE6F . 8BE5 MOV ESP,EBP 013BDE71 . 5D POP EBP ; 0584FD48 013BDE72 . C2 0800 RETN 0x8
上述代码中,将返回值低八位和key[ n ]进行比较,每次比较完后右移八位,再次比较新数值的低八位。总共比较4次,正好将32位返回值全部比对完。
在第三步分析0x9C分支中已经得到 [EDI+0x1C] = ecx = (key[0]^key[6]^0x18+0x3D)^0xA7,
局部变量 [ EBP+0x8 ] = 9。
局部变量[ EBP - 0x10] 为第三步中分析AC分支返回eax得到,
eax = ((((key[1]^key[7]) * 0x100 + key[2]^key[5])^0x7892 + 0x4D30)^0x3421)/0xB;
局部变量 [ EBP+0xC ] = 4389。
转换为C代码为
//将返回值看成为一个数组,nArray[4] if((nArray[0]==key[4]) && (nArray[1]==key[5]) && (nArray[2]==key[6]) && (nArray[3]==key[7])) { if(key[3]==0x9C) { //[EDI+0x1C] = (key[0]^key[6]^0x18+0x3D)^0xA7; if(9 <= (key[0]^key[6]^0x18+0x3D)^0xA7)) { return 0x2D; //验证成功 } return 0x4E; //验证失败 } else if(key[3]==0xFC) { return 0xE7; //验证失败 } else if(key[3]=0xAC) { if([ebp - 10] >= 4389) { return 0x2D; //验证成功 } return 0x4E; //验证失败 } }