-
-
[原创]看雪CTF.TSRC 2018 团队赛 第四题 WP
-
发表于: 2018-12-9 10:35 3556
-
一、2处反调试
1、如果没有发现反调试则修改D316BD开始2字节为:EB0D,这部分代码如下
signed int sub_DC1010() { HANDLE v0; // eax v0 = GetCurrentProcess(); g_NtQueryInformationProcessAddr(v0, 30, &g_debugFlag, 4, 0); return sub_DC1035(); } signed int sub_DC104F() { signed int result; // eax if ( !g_debugFlag ) { loc_D316BD = 0xEBu; result = 0xD316BE; *(&loc_D316BD + 1) = 0xD; } return result; } .text:00D316BD EB 0D jmp short loc_D316CC .text:00D316BD ; --------------------------------------------------------------------------- .text:00D316BF AC db 0ACh .text:00D316C0 DB db 0DBh .text:00D316C1 DA db 0DAh .text:00D316C2 ; --------------------------------------------------------------------------- .text:00D316C2 FF 15 00 A0 DD 00 call ds:IsDebuggerPresent
如果没发现反调试则直接跳转,不过这不影响分析,因为主要check函数在这上面
2 如下:
.text:00D31D63 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31D69 85 5D EC test [ebp-14h], ebx .text:00D31D6C 90 nop .text:00D31D6D 8B 40 30 mov eax, [eax+30h] .text:00D31D70 F5 cmc .text:00D31D71 0F BA E3 0C bt ebx, 0Ch .text:00D31D75 0F B6 40 02 movzx eax, byte ptr [eax+2] ;如果存在调试 EAX=1
如果上面的EAX=1 则会影响下面的地址计算。
二、main
int __cdecl main(int argc, const char **argv, const char **envp) { char sn[32]; // [esp+0h] [ebp-28h] std::cout(aPlzInputYourSe, sn[0]); GetInputSn(a32s, (unsigned int)sn); if ( check(sn) ) std::cout(aCongratulation, sn[0]); else std::cout(aWrongSerialYou, sn[0]); sub_DCA68B(aPause); return 0; }
1、读取sn sn缓冲区大小为32字节。
2、check函数返回1表示校验成功。
三、check函数
BOOL __cdecl check(char *sn) { char sn1[8]; // [esp+10h] [ebp-1D0h] int i; // [esp+18h] [ebp-1C8h] char v5[64]; // [esp+1Ch] [ebp-1C4h] char v6[64]; // [esp+5Ch] [ebp-184h] char v7[64]; // [esp+9Ch] [ebp-144h] char v8[256]; // [esp+DCh] [ebp-104h] *(_DWORD *)sn1 = 0; *(_DWORD *)&sn1[4] = 0; sub_DC2140((__m128i *)v7, 0, 0x40u); *(_DWORD *)v8 = 0; *(_DWORD *)&v8[196] = 0; *(_DWORD *)&v8[200] = 0; *(_DWORD *)&v8[204] = 0; *(_DWORD *)&v8[208] = 10; *(_DWORD *)&v8[212] = 15; *(_DWORD *)&v8[216] = 2; *(_DWORD *)&v8[220] = 13; *(_DWORD *)&v8[224] = 10; *(_DWORD *)&v8[228] = 8; *(_DWORD *)&v8[232] = 6; *(_DWORD *)&v8[236] = 15; *(_DWORD *)&v8[240] = 0; *(_DWORD *)&v8[244] = 5; *(_DWORD *)&v8[248] = 3; *(_DWORD *)&v8[252] = 0; *(_DWORD *)&v8[128] = 16; *(_DWORD *)&v8[132] = 0; *(_DWORD *)&v8[136] = 16; *(_DWORD *)&v8[140] = 14; *(_DWORD *)&v8[144] = 3; *(_DWORD *)&v8[148] = 10; *(_DWORD *)&v8[152] = 6; *(_DWORD *)&v8[156] = 0; *(_DWORD *)&v8[160] = 0; *(_DWORD *)&v8[164] = 7; *(_DWORD *)&v8[168] = 13; *(_DWORD *)&v8[172] = 6; *(_DWORD *)&v8[176] = 4; *(_DWORD *)&v8[180] = 7; *(_DWORD *)&v8[184] = 0; *(_DWORD *)&v8[188] = 2; *(_DWORD *)&v8[64] = 6; *(_DWORD *)&v8[68] = 16; *(_DWORD *)&v8[72] = 0; *(_DWORD *)&v8[76] = 12; *(_DWORD *)&v8[80] = 0; *(_DWORD *)&v8[84] = 11; *(_DWORD *)&v8[88] = 16; *(_DWORD *)&v8[92] = 12; *(_DWORD *)&v8[96] = 8; *(_DWORD *)&v8[100] = 12; *(_DWORD *)&v8[104] = 12; *(_DWORD *)&v8[108] = 0; *(_DWORD *)&v8[112] = 6; *(_DWORD *)&v8[116] = 0; *(_DWORD *)&v8[120] = 11; *(_DWORD *)&v8[124] = 13; *(_DWORD *)v8 = 16; *(_DWORD *)&v8[4] = 14; *(_DWORD *)&v8[8] = 13; *(_DWORD *)&v8[12] = 14; *(_DWORD *)&v8[16] = 4; *(_DWORD *)&v8[20] = 0; *(_DWORD *)&v8[24] = 0; *(_DWORD *)&v8[28] = 16; *(_DWORD *)&v8[32] = 5; *(_DWORD *)&v8[36] = 0; *(_DWORD *)&v8[40] = 0; *(_DWORD *)&v8[44] = 3; *(_DWORD *)&v8[48] = 5; *(_DWORD *)&v8[52] = 16; *(_DWORD *)&v8[56] = 14; *(_DWORD *)&v8[60] = 16; sub_DC2140((__m128i *)v5, 0, 0x40u); *(_DWORD *)v6 = 222105; *(_DWORD *)&v6[4] = 494358; *(_DWORD *)&v6[8] = 443201; *(_DWORD *)&v6[12] = 423901; *(_DWORD *)&v6[16] = 310311; *(_DWORD *)&v6[20] = 700114; *(_DWORD *)&v6[24] = 629640; *(_DWORD *)&v6[28] = 620483; *(_DWORD *)&v6[32] = 301566; *(_DWORD *)&v6[36] = 676368; *(_DWORD *)&v6[40] = 606711; *(_DWORD *)&v6[44] = 605590; *(_DWORD *)&v6[48] = 149250; *(_DWORD *)&v6[52] = 339264; *(_DWORD *)&v6[56] = 304846; *(_DWORD *)&v6[60] = 301296; if ( strlen(sn) != 16 ) return 0; for ( i = 0; i < 16; ++i ) { if ( (sn[i] < 48 || sn[i] > 57) && (sn[i] < 65 || sn[i] > 70) ) return 0; } for ( i = 0; i < 8; ++i ) { if ( sn[i] < 48 || sn[i] > 57 ) *(_DWORD *)sn1 += (sn[i] - 55) << (28 - 4 * i); else *(_DWORD *)sn1 += (sn[i] - 48) << (28 - 4 * i); if ( sn[i + 8] < 48 || sn[i + 8] > 57 ) *(_DWORD *)&sn1[4] += (sn[i + 8] - 55) << (28 - 4 * i); else *(_DWORD *)&sn1[4] += (sn[i + 8] - 48) << (28 - 4 * i); } sub_D31C70( sn1, aOneShallStandA, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, &v8[192], 0xDEADBEEF); sub_D93120(); return *(_DWORD *)sn1 == 0x87654321 && *(_DWORD *)&sn1[4] == 0x12345678; }
1、前面一大堆初始化的数据没啥用。
2、判断sn长度不等16则返回0
3、判断sn 是否是 0-9 A-F,不是返回0
4、将输入的字符串转换成2个int整数。
5、然后调用压入了貌似各种加密算法的数据以及一个字符串"One shall stand and one shall fall",不是你死就是我亡。
6、这些数据有的像MD5,有的像SM3,各种算法;
7、调用sub_D31C70
8、然后判断sn1 == 0x87654321 sn2 == 0x12345678,如果相等,则返回真。因此
sub_D31C70会将sn加密。
四、
sub_D31C70加密函数
(一)垃圾指令与SMC
1、进去这个函数好大,
将近40K ,IDA没法识别。各种垃圾指令,而且还存在SMC,自修改代码。但是稍微分析下这些垃圾指令还是有规律的,比如:
;取出参数局部变量. text:00D31C91 BF 77 88 8C 60 mov edi, 608C8877h .text:00D31C96 81 EF A9 A3 67 D3 sub edi, 0D367A3A9h .text:00D31C9C 81 EF 61 55 D2 99 sub edi, 99D25561h .text:00D31CA2 81 EF 39 16 BF F8 sub edi, 0F8BF1639h .text:00D31CA8 81 EF 03 5E 7B 5E sub edi, 5E7B5E03h .text:00D31CAE 8B 8C FD 8C 26 3F 1F mov ecx, [ebp+edi*8+1F3F268Ch] ; sn1
2、SMC自修改代码
push eax
----------
push ebx
-----------
push ecx
一直到
pop ecx
pop ebx
pop eax
代码解密结束。
.text:00D31F3B 50 push eax .text:00D31F3C 83 C9 00 or ecx, 0 .text:00D31F3F FC cld .text:00D31F40 53 push ebx .text:00D31F41 FC cld .text:00D31F42 F5 cmc .text:00D31F43 51 push ecx .text:00D31F44 85 F8 test eax, edi .text:00D31F46 90 nop .text:00D31F47 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31F4D 39 EB cmp ebx, ebp .text:00D31F4F 83 E1 FF and ecx, 0FFFFFFFFh .text:00D31F52 8B 40 30 mov eax, [eax+30h] .text:00D31F55 F7 C3 2C 0B EE 23 test ebx, 23EE0B2Ch .text:00D31F5B F5 cmc .text:00D31F5C 0F B6 40 02 movzx eax, byte ptr [eax+2] .text:00D31F60 90 nop .text:00D31F61 81 FD 84 48 6F 2D cmp ebp, 2D6F4884h .text:00D31F67 BB 00 00 00 00 mov ebx, 0 .text:00D31F6C .text:00D31F6C loc_D31F6C: ; CODE XREF: .text:00D31F7D↓j .text:00D31F6C 43 inc ebx .text:00D31F6D 39 C7 cmp edi, eax .text:00D31F6F F9 stc .text:00D31F70 83 C3 01 add ebx, 1 .text:00D31F73 F5 cmc .text:00D31F74 85 55 9C test [ebp-64h], edx .text:00D31F77 81 FB DA 94 0E 00 cmp ebx, 0E94DAh .text:00D31F7D 72 ED jb short loc_D31F6C .text:00D31F7F E8 00 00 00 00 call $+5 .text:00D31F84 5E pop esi .text:00D31F85 01 C6 add esi, eax .text:00D31F87 81 C6 70 E5 6C 88 add esi, 886CE570h .text:00D31F8D 81 C6 D6 30 78 14 add esi, 147830D6h .text:00D31F93 81 C6 08 55 23 93 add esi, 93235508h .text:00D31F99 81 C6 29 52 56 EB add esi, 0EB565229h .text:00D31F9F 81 C6 C0 42 A1 E4 add esi, 0E4A142C0h .text:00D31FA5 FF E6 jmp esi .text:00D31FA5 ; --------------------------------------------------------------------------- .text:00D31FA7 2B db 2Bh ; + .text:00D31FA8 ; --------------------------------------------------------------------------- .text:00D31FA8 55 push ebp .text:00D31FA9 1C 8B sbb al, 8Bh .text:00D31FAB 55 push ebp .text:00D31FAC F8 clc .text:00D31FAD 03 55 F4 add edx, [ebp-0Ch] .text:00D31FB0 8B 55 FC mov edx, [ebp-4] .text:00D31FB3 C1 E2 04 shl edx, 4 .text:00D31FB6 31 D0 xor eax, edx .text:00D31FB8 C1 E0 05 shl eax, 5 .text:00D31FBB B9 C4 00 00 00 mov ecx, 0C4h .text:00D31FC0 E8 00 00 00 00 call $+5 .text:00D31FC5 58 pop eax .text:00D31FC6 83 C0 71 add eax, 71h .text:00D31FC9 83 E8 0B sub eax, 0Bh .text:00D31FCC 32 08 xor cl, [eax] .text:00D31FCE 83 E8 0E sub eax, 0Eh .text:00D31FD1 02 08 add cl, [eax] .text:00D31FD3 83 E8 09 sub eax, 9 .text:00D31FD6 32 08 xor cl, [eax] .text:00D31FD8 83 E8 0E sub eax, 0Eh .text:00D31FDB 02 08 add cl, [eax] .text:00D31FDD 83 E8 0A sub eax, 0Ah .text:00D31FE0 32 08 xor cl, [eax] .text:00D31FE2 83 E8 09 sub eax, 9 .text:00D31FE5 32 08 xor cl, [eax] .text:00D31FE7 83 E8 0C sub eax, 0Ch .text:00D31FEA 2A 08 sub cl, [eax] .text:00D31FEC 83 E8 0B sub eax, 0Bh .text:00D31FEF 02 08 add cl, [eax] .text:00D31FF1 83 E8 0B sub eax, 0Bh .text:00D31FF4 02 08 add cl, [eax] .text:00D31FF6 83 E8 08 sub eax, 8 .text:00D31FF9 2A 08 sub cl, [eax] .text:00D31FFB E8 00 00 00 00 call $+5 .text:00D32000 58 pop eax .text:00D32001 83 C0 36 add eax, 36h .text:00D32004 83 C0 0B add eax, 0Bh .text:00D32007 28 08 sub [eax], cl .text:00D32009 83 C0 0B add eax, 0Bh .text:00D3200C 28 08 sub [eax], cl .text:00D3200E 83 C0 07 add eax, 7 .text:00D32011 30 08 xor [eax], cl .text:00D32013 83 C0 0C add eax, 0Ch .text:00D32016 28 08 sub [eax], cl .text:00D32018 83 C0 07 add eax, 7 .text:00D3201B 30 08 xor [eax], cl .text:00D3201D 83 C0 0F add eax, 0Fh .text:00D32020 30 08 xor [eax], cl .text:00D32022 83 C0 09 add eax, 9 .text:00D32025 00 08 add [eax], cl .text:00D32027 83 C0 0C add eax, 0Ch .text:00D3202A 00 08 add [eax], cl .text:00D3202C 83 C0 07 add eax, 7 .text:00D3202F 00 08 add [eax], cl .text:00D32031 83 C0 09 add eax, 9 .text:00D32034 28 08 sub [eax], cl .text:00D32036 59 pop ecx .text:00D32037 5B pop ebx .text:00D32038 58 pop eax
可以写个脚本从push ecx 下面开直接跳转到pop ecx位置。不想分析SMC解密算法了,可以先让程序执行一遍,等待代码解密完成,然后用脚本将解密代码跳过,再重新跳转到输入SN位置,再次输入SN,进行分析。下面是相关脚本:
import struct from idaapi import * from idc import * from idautils import * '''==================================================== 函数名:GetLibAddr 用 途:根据模块名获得模块起始地址 备 注:此函数在SHT被破坏时将不起作用 =====================================================''' def GetLibAddr(targetName): targetBase = 0 for i in Modules(): #print i.name if targetName in i.name: targetBase = int("%x"%(i.base), 16) #print 'targetName:=' + targetName + 'targetBase:=' + str(targetBase) break if targetBase == 0: #print 'targetBase None!!!' return False return targetBase '''==================================================== 函数名:GetSegAddrByName 用 途:根据段名获得段的起始地址 备 注: =====================================================''' def GetSegAddrByName(targetName): tempAddr = FirstSeg() while tempAddr!=0: if tempAddr == 0: break name = SegName(tempAddr) if targetName in name: return tempAddr tempAddr = NextSeg(tempAddr) return 0 '''==================================================== 函数名:writeMemoryForAddr 用 途:向模块地址写入指定shellcode 备 注: =====================================================''' def writeMemoryForAddr(targetName, offset, buf): targetBase = 0 targetBase = GetSegAddrByName(targetName) if targetBase == 0: #print 'targetBase None!!!' return False addr = targetBase + offset if not dbg_write_memory(addr, buf): return False refresh_debugger_memory() return True '''==================================================== 函数名:FindData 用 途:从指定位置查找指定字节的数据 备 注:返回第一个找到的位置 =====================================================''' def FindData(addr, target): a = -1 segStart = SegStart(addr) segEnd = SegEnd(addr) len=segEnd-segStart for i in range(len): rawdex1 = idaapi.dbg_read_memory(addr, 1024) a = rawdex1.find(target) if a>= 0: a = a + addr break; addr = addr+512 return a '''==================================================== 函数名:makeAllCode 用 途:设置为代码 备 注:返回第一个找到的位置 =====================================================''' def makeAllCode(ea, len): while ea < ea + len: print str(hex(ea)) MakeCode(ea) instring = GetDisasm(ea) inslen = ida_ua.decode_insn(insn, ea) print instring ea = ea + inslen print 'start' startAddr = GetLibAddr('transformer.exe') + 0x1C70 endAddr = startAddr + 0x5A38C cnt = 0 pushEcxString = 'push ecx' jmpEaxString = 'jmp esi' wireCode = '\x58\x83\xC0\x36\x83\xC0\x0E\x28\x08\x83\xC0\x0E\x28\x08\x83\xC0' libAddr = GetLibAddr('transformer.exe') writeAddr = libAddr + 0x8741; pushEcxAddr = 0 lastpopAddr = startAddr print 'jmpLoopAddr = ' + str(hex(libAddr + 0x1B2C)) dbg_write_memory(libAddr + 0x1B2C, '\xeb\xd2') refresh_debugger_memory() print 'antiDebugAddr = ' + str(hex(libAddr + 0x6bd)) dbg_write_memory(libAddr + 0x16bd, '\xeb\x0d') refresh_debugger_memory() while startAddr < endAddr: popAddr = FindData(startAddr, '\x59\x5b\x58') print 'prepopAddr = ' + str(hex(lastpopAddr)) print 'curpopAddr = ' + str(hex(popAddr)) if 0 == popAddr : print 'find ok' break; flag = 0 while lastpopAddr < popAddr: instring = GetDisasm(lastpopAddr) if instring == jmpEaxString: MakeCode(lastpopAddr + 2) if instring == pushEcxString: pushEcxAddr = lastpopAddr flag = 1 break lastpopAddr = lastpopAddr + 1 if flag == 0 : print 'no find push ecx' break lastpopAddr = popAddr print 'pushAddr = ' + str(hex(pushEcxAddr)) offset = popAddr - pushEcxAddr - 6; opcode = '\xE9' + struct.pack('I', offset) dbg_write_memory(pushEcxAddr + 1, opcode) refresh_debugger_memory() break; cnt = cnt + 1 startAddr = popAddr + 3 print cnt print 'finish'
一共发现600多处自修改的地方 ,而且在偏移0x8741位置的代码执行完又被后面的改了,当时以为其执行完会破坏以前的代码。但是好像就这一处。因此
先将这个被修改的代码改回来执行脚本
可以先使用 MakeAllCode跑一下,让IDA将数据识别成代码,然后再执行(指令修改)。
注(在算法要结束位置,程序将计算出来的一些临时数据写入到 0x8745偏移一共16个BYTE,貌似没啥用处)。
执行完后发现代码仍然很大,没时间再简化了,就放弃了,还是直接分析吧。。。。
(二)
sub_D31C70分析
1、直接上OD调试。在输入SN位置下访问断点、写入断点,可以很块定位到核心算法位置。
00B284B6 . 89847D DEE3E3>mov dword ptr ss:[ebp+edi*2-0x121C1C22],eax 00B284BD . 85C1 test ecx,eax 00B284BF . BF 31987B38 mov edi,0x387B9831 00B284C4 . 81EF 2BE69E53 sub edi,0x539EE62B 00B284CA . 81EF 3065DE2B sub edi,0x2BDE6530 00B284D0 . C7847D 486603>mov dword ptr ss:[ebp+edi*2-0x71FC99B8],0x0 00B284DB . BF 4BAE0B01 mov edi,0x10BAE4B ; UNICODE "一" 00B284E0 . 81EF 4504CB80 sub edi,0x80CB0445 00B284E6 . 81EF EDDCB6C5 sub edi,0xC5B6DCED 00B284EC . 81EF BBC4D83C sub edi,0x3CD8C4BB 00B284F2 . 81EF 9C09F68E sub edi,0x8EF6099C 00B284F8 . C784BD DC0414>mov dword ptr ss:[ebp+edi*4+0x451404DC],0x89ABCDEF 00B28503 . BF 5BBDAB83 mov edi,0x83ABBD5B 00B28508 . 81EF C05401A2 sub edi,0xA20154C0 00B2850E . 81EF 80FEEEBA sub edi,0xBAEEFE80
发现将SN存储到局部变量中如下:
00DAF5E0 00B28281 返回到 transfor.00B28281 来自 transfor.00B28281 00DAF5E4 00000004 00DAF5E8 12345678 ;sn2 00DAF5EC 12345678 ;sn1 00DAF5F0 00DAF808 00DAF5F4 00B016B5 返回到 transfor.00B016B5 来自 transfor.00B01C70 00DAF5F8 00DAF638 00DAF5FC 00BB1000 ASCII "One shall stand and one shall fall." 00DAF600 67452301 00DAF604 EFCDAB89 00DAF608 98BADCFE 00DAF60C 10325476 00DAF610 7380166F 00DAF614 4914B2B9 00DAF618 172442D7 00DAF61C DA8A0600 00DAF620 00B08741 transfor.00B08741 00DAF624 63BFC7EA
这个函数的大概流程如下:
1、反调试,然后代码自解密;
2、前面大片都是垃圾代码;
3、可以对SN下访问断点开始跟踪;
4、写入多个常量数据到堆栈;
5、从上面写入的多个常量数据中取出2个用于运算使用,此时堆栈结构如下:
007CF9C0 12345678 //中间用于运算的 实际没有,最后这个值写入到 0x8745偏移地址 007CF9C4 AAAAAAAA //中间用于运算的 实际没有,最后这个值写入到 0x8745偏移地址 007CF9C8 20646E61 //One shall stand and one shall fall中的 007CF9CC 7473206C //One shall stand and one shall fall中的 007CF9D0 20656E4F //One shall stand and one shall fall中的 007CF9D4 89ABCDEF //用于计算的slat 007CF9D8 6C616873 //One shall stand and one shall fall中的 007CF9DC B4FB26B3 //从前面写入的多个常量数据中取出 007CF9E0 EB0B932A ////从前面写入的多个常量数据中取出 007CF9E4 89ABCDEF //用于计算的slat 007CF9E8 AAAAAAAA 输入sn2 //加密数据 007CF9EC 12345678 输入sn1 //加密数据
6、算法比较简单,就是混淆的比较多,耐心分析一下,流程还是很简单的。下面是逆向出来的源码,其中一些用于加密的常量是中间计算出来,我列在下面算法中。
7、先逆向出来加密算法,解密算法就很简单了。
bool encodeData(unsigned int sn1, unsigned int sn2, int* outSn) { unsigned int tempKey1; unsigned int tempKey2; unsigned int tempKey3; unsigned int key1 = sn1; unsigned int key2 = sn2; unsigned int str1 = 0x20656E4F; unsigned int str2 = 0x6C616873; unsigned int str3 = 0x7473206C; unsigned int str4 = 0x20646E61; unsigned int salt = 0x89ABCDEF; unsigned int sn1Salt[8] = { 0xC3DABC80, 0x5EEA6480, 0x70DAFF, 0x98274F00, 0x0C412072, 0x369607A0, 0x30AA34 }; unsigned int sn2Salt[8] = { 0x00325E4D, 0x1724D6F7, 0x32A48390, 0x3623FDE0, 0x2DC55FB, 0x0393E1BB, 0xABB89880}; for(int i = 0; i < 8; i++) { tempKey1 = (key2 << 4) + str1; tempKey2 = key2 + salt; tempKey1 = tempKey1 ^ tempKey2; tempKey3 = (key2 >> 5) +str2;; tempKey1 = tempKey1 ^ tempKey3; key1 += tempKey1; tempKey1 = (key1 << 4) + str3; tempKey2 = key1; tempKey2 = key1 + salt; tempKey1 = tempKey1 ^ tempKey2; tempKey3 = (key1 >> 5) + str4; tempKey1 = tempKey1 ^ tempKey3; key2 += tempKey1; if (i < 7) { key1 = key1 - sn1Salt[i]; key2 = key2 - sn2Salt[i]; } salt = salt + 0x89ABCDEF; } outSn[0] = key1; outSn[1] = key2; return false; } bool decryptData(unsigned int sn1, unsigned int sn2, int* outSn) { unsigned int tempKey1; unsigned int tempKey2; unsigned int tempKey3; unsigned int key1 = sn1; unsigned int key2 = sn2; unsigned int str1 = 0x20656E4F; unsigned int str2 = 0x6C616873; unsigned int str3 = 0x7473206C; unsigned int str4 = 0x20646E61; unsigned int salt = 0x4D5E6F78; unsigned int sn1Salt[8] = { 0xC3DABC80, 0x5EEA6480, 0x70DAFF, 0x98274F00, 0x0C412072, 0x369607A0, 0x30AA34 }; unsigned int sn2Salt[8] = { 0x00325E4D, 0x1724D6F7, 0x32A48390, 0x3623FDE0, 0x2DC55FB, 0x0393E1BB, 0xABB89880 }; for (int i = 7; i >= 0; i--) { tempKey1 = (key1 << 4) + str3; tempKey2 = key1; tempKey2 = key1 + salt; tempKey1 = tempKey1 ^ tempKey2; tempKey3 = (key1 >> 5) + str4; tempKey1 = tempKey1 ^ tempKey3; key2 -= tempKey1; tempKey1 = (key2 << 4) + str1; tempKey2 = key2 + salt; tempKey1 = tempKey1 ^ tempKey2; tempKey3 = (key2 >> 5) + str2;; tempKey1 = tempKey1 ^ tempKey3; key1 -= tempKey1; if (i > 0) { key2 += sn2Salt[i-1]; key1 += sn1Salt[i-1]; } salt = salt - 0x89ABCDEF; } outSn[0] = key1; outSn[1] = key2; return false; }
SN = 285764B86F41B019
signed int sub_DC1010() { HANDLE v0; // eax v0 = GetCurrentProcess(); g_NtQueryInformationProcessAddr(v0, 30, &g_debugFlag, 4, 0); return sub_DC1035(); } signed int sub_DC104F() { signed int result; // eax if ( !g_debugFlag ) { loc_D316BD = 0xEBu; result = 0xD316BE; *(&loc_D316BD + 1) = 0xD; } return result; } .text:00D316BD EB 0D jmp short loc_D316CC .text:00D316BD ; --------------------------------------------------------------------------- .text:00D316BF AC db 0ACh .text:00D316C0 DB db 0DBh .text:00D316C1 DA db 0DAh .text:00D316C2 ; --------------------------------------------------------------------------- .text:00D316C2 FF 15 00 A0 DD 00 call ds:IsDebuggerPresent
如果没发现反调试则直接跳转,不过这不影响分析,因为主要check函数在这上面
2 如下:
.text:00D31D63 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31D69 85 5D EC test [ebp-14h], ebx .text:00D31D6C 90 nop .text:00D31D6D 8B 40 30 mov eax, [eax+30h] .text:00D31D70 F5 cmc .text:00D31D71 0F BA E3 0C bt ebx, 0Ch .text:00D31D75 0F B6 40 02 movzx eax, byte ptr [eax+2] ;如果存在调试 EAX=1
如果上面的EAX=1 则会影响下面的地址计算。
二、main
int __cdecl main(int argc, const char **argv, const char **envp) { char sn[32]; // [esp+0h] [ebp-28h] std::cout(aPlzInputYourSe, sn[0]); GetInputSn(a32s, (unsigned int)sn); if ( check(sn) ) std::cout(aCongratulation, sn[0]); else std::cout(aWrongSerialYou, sn[0]); sub_DCA68B(aPause); return 0; }
1、读取sn sn缓冲区大小为32字节。
2、check函数返回1表示校验成功。
三、check函数
BOOL __cdecl check(char *sn) { char sn1[8]; // [esp+10h] [ebp-1D0h] int i; // [esp+18h] [ebp-1C8h] char v5[64]; // [esp+1Ch] [ebp-1C4h] char v6[64]; // [esp+5Ch] [ebp-184h] char v7[64]; // [esp+9Ch] [ebp-144h] char v8[256]; // [esp+DCh] [ebp-104h] *(_DWORD *)sn1 = 0; *(_DWORD *)&sn1[4] = 0; sub_DC2140((__m128i *)v7, 0, 0x40u); *(_DWORD *)v8 = 0; *(_DWORD *)&v8[196] = 0; *(_DWORD *)&v8[200] = 0; *(_DWORD *)&v8[204] = 0; *(_DWORD *)&v8[208] = 10; *(_DWORD *)&v8[212] = 15; *(_DWORD *)&v8[216] = 2; *(_DWORD *)&v8[220] = 13; *(_DWORD *)&v8[224] = 10; *(_DWORD *)&v8[228] = 8; *(_DWORD *)&v8[232] = 6; *(_DWORD *)&v8[236] = 15; *(_DWORD *)&v8[240] = 0; *(_DWORD *)&v8[244] = 5; *(_DWORD *)&v8[248] = 3; *(_DWORD *)&v8[252] = 0; *(_DWORD *)&v8[128] = 16; *(_DWORD *)&v8[132] = 0; *(_DWORD *)&v8[136] = 16; *(_DWORD *)&v8[140] = 14; *(_DWORD *)&v8[144] = 3; *(_DWORD *)&v8[148] = 10; *(_DWORD *)&v8[152] = 6; *(_DWORD *)&v8[156] = 0; *(_DWORD *)&v8[160] = 0; *(_DWORD *)&v8[164] = 7; *(_DWORD *)&v8[168] = 13; *(_DWORD *)&v8[172] = 6; *(_DWORD *)&v8[176] = 4; *(_DWORD *)&v8[180] = 7; *(_DWORD *)&v8[184] = 0; *(_DWORD *)&v8[188] = 2; *(_DWORD *)&v8[64] = 6; *(_DWORD *)&v8[68] = 16; *(_DWORD *)&v8[72] = 0; *(_DWORD *)&v8[76] = 12; *(_DWORD *)&v8[80] = 0; *(_DWORD *)&v8[84] = 11; *(_DWORD *)&v8[88] = 16; *(_DWORD *)&v8[92] = 12; *(_DWORD *)&v8[96] = 8; *(_DWORD *)&v8[100] = 12; *(_DWORD *)&v8[104] = 12; *(_DWORD *)&v8[108] = 0; *(_DWORD *)&v8[112] = 6; *(_DWORD *)&v8[116] = 0; *(_DWORD *)&v8[120] = 11; *(_DWORD *)&v8[124] = 13; *(_DWORD *)v8 = 16; *(_DWORD *)&v8[4] = 14; *(_DWORD *)&v8[8] = 13; *(_DWORD *)&v8[12] = 14; *(_DWORD *)&v8[16] = 4; *(_DWORD *)&v8[20] = 0; *(_DWORD *)&v8[24] = 0; *(_DWORD *)&v8[28] = 16; *(_DWORD *)&v8[32] = 5; *(_DWORD *)&v8[36] = 0; *(_DWORD *)&v8[40] = 0; *(_DWORD *)&v8[44] = 3; *(_DWORD *)&v8[48] = 5; *(_DWORD *)&v8[52] = 16; *(_DWORD *)&v8[56] = 14; *(_DWORD *)&v8[60] = 16; sub_DC2140((__m128i *)v5, 0, 0x40u); *(_DWORD *)v6 = 222105; *(_DWORD *)&v6[4] = 494358; *(_DWORD *)&v6[8] = 443201; *(_DWORD *)&v6[12] = 423901; *(_DWORD *)&v6[16] = 310311; *(_DWORD *)&v6[20] = 700114; *(_DWORD *)&v6[24] = 629640; *(_DWORD *)&v6[28] = 620483; *(_DWORD *)&v6[32] = 301566; *(_DWORD *)&v6[36] = 676368; *(_DWORD *)&v6[40] = 606711; *(_DWORD *)&v6[44] = 605590; *(_DWORD *)&v6[48] = 149250; *(_DWORD *)&v6[52] = 339264; *(_DWORD *)&v6[56] = 304846; *(_DWORD *)&v6[60] = 301296; if ( strlen(sn) != 16 ) return 0; for ( i = 0; i < 16; ++i ) { if ( (sn[i] < 48 || sn[i] > 57) && (sn[i] < 65 || sn[i] > 70) ) return 0; } for ( i = 0; i < 8; ++i ) { if ( sn[i] < 48 || sn[i] > 57 ) *(_DWORD *)sn1 += (sn[i] - 55) << (28 - 4 * i); else *(_DWORD *)sn1 += (sn[i] - 48) << (28 - 4 * i); if ( sn[i + 8] < 48 || sn[i + 8] > 57 ) *(_DWORD *)&sn1[4] += (sn[i + 8] - 55) << (28 - 4 * i); else *(_DWORD *)&sn1[4] += (sn[i + 8] - 48) << (28 - 4 * i); } sub_D31C70( sn1, aOneShallStandA, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, &v8[192], 0xDEADBEEF); sub_D93120(); return *(_DWORD *)sn1 == 0x87654321 && *(_DWORD *)&sn1[4] == 0x12345678; }
1、前面一大堆初始化的数据没啥用。
2、判断sn长度不等16则返回0
3、判断sn 是否是 0-9 A-F,不是返回0
4、将输入的字符串转换成2个int整数。
5、然后调用压入了貌似各种加密算法的数据以及一个字符串"One shall stand and one shall fall",不是你死就是我亡。
6、这些数据有的像MD5,有的像SM3,各种算法;
7、调用sub_D31C70
8、然后判断sn1 == 0x87654321 sn2 == 0x12345678,如果相等,则返回真。因此
sub_D31C70会将sn加密。
四、
sub_D31C70加密函数
.text:00D31D63 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31D69 85 5D EC test [ebp-14h], ebx .text:00D31D6C 90 nop .text:00D31D6D 8B 40 30 mov eax, [eax+30h] .text:00D31D70 F5 cmc .text:00D31D71 0F BA E3 0C bt ebx, 0Ch .text:00D31D75 0F B6 40 02 movzx eax, byte ptr [eax+2] ;如果存在调试 EAX=1
如果上面的EAX=1 则会影响下面的地址计算。
二、main
int __cdecl main(int argc, const char **argv, const char **envp) { char sn[32]; // [esp+0h] [ebp-28h] std::cout(aPlzInputYourSe, sn[0]); GetInputSn(a32s, (unsigned int)sn); if ( check(sn) ) std::cout(aCongratulation, sn[0]); else std::cout(aWrongSerialYou, sn[0]); sub_DCA68B(aPause); return 0; }
1、读取sn sn缓冲区大小为32字节。
int __cdecl main(int argc, const char **argv, const char **envp) { char sn[32]; // [esp+0h] [ebp-28h] std::cout(aPlzInputYourSe, sn[0]); GetInputSn(a32s, (unsigned int)sn); if ( check(sn) ) std::cout(aCongratulation, sn[0]); else std::cout(aWrongSerialYou, sn[0]); sub_DCA68B(aPause); return 0; }
1、读取sn sn缓冲区大小为32字节。
2、check函数返回1表示校验成功。
三、check函数
BOOL __cdecl check(char *sn) { char sn1[8]; // [esp+10h] [ebp-1D0h] int i; // [esp+18h] [ebp-1C8h] char v5[64]; // [esp+1Ch] [ebp-1C4h] char v6[64]; // [esp+5Ch] [ebp-184h] char v7[64]; // [esp+9Ch] [ebp-144h] char v8[256]; // [esp+DCh] [ebp-104h] *(_DWORD *)sn1 = 0; *(_DWORD *)&sn1[4] = 0; sub_DC2140((__m128i *)v7, 0, 0x40u); *(_DWORD *)v8 = 0; *(_DWORD *)&v8[196] = 0; *(_DWORD *)&v8[200] = 0; *(_DWORD *)&v8[204] = 0; *(_DWORD *)&v8[208] = 10; *(_DWORD *)&v8[212] = 15; *(_DWORD *)&v8[216] = 2; *(_DWORD *)&v8[220] = 13; *(_DWORD *)&v8[224] = 10; *(_DWORD *)&v8[228] = 8; *(_DWORD *)&v8[232] = 6; *(_DWORD *)&v8[236] = 15; *(_DWORD *)&v8[240] = 0; *(_DWORD *)&v8[244] = 5; *(_DWORD *)&v8[248] = 3; *(_DWORD *)&v8[252] = 0; *(_DWORD *)&v8[128] = 16; *(_DWORD *)&v8[132] = 0; *(_DWORD *)&v8[136] = 16; *(_DWORD *)&v8[140] = 14; *(_DWORD *)&v8[144] = 3; *(_DWORD *)&v8[148] = 10; *(_DWORD *)&v8[152] = 6; *(_DWORD *)&v8[156] = 0; *(_DWORD *)&v8[160] = 0; *(_DWORD *)&v8[164] = 7; *(_DWORD *)&v8[168] = 13; *(_DWORD *)&v8[172] = 6; *(_DWORD *)&v8[176] = 4; *(_DWORD *)&v8[180] = 7; *(_DWORD *)&v8[184] = 0; *(_DWORD *)&v8[188] = 2; *(_DWORD *)&v8[64] = 6; *(_DWORD *)&v8[68] = 16; *(_DWORD *)&v8[72] = 0; *(_DWORD *)&v8[76] = 12; *(_DWORD *)&v8[80] = 0; *(_DWORD *)&v8[84] = 11; *(_DWORD *)&v8[88] = 16; *(_DWORD *)&v8[92] = 12; *(_DWORD *)&v8[96] = 8; *(_DWORD *)&v8[100] = 12; *(_DWORD *)&v8[104] = 12; *(_DWORD *)&v8[108] = 0; *(_DWORD *)&v8[112] = 6; *(_DWORD *)&v8[116] = 0; *(_DWORD *)&v8[120] = 11; *(_DWORD *)&v8[124] = 13; *(_DWORD *)v8 = 16; *(_DWORD *)&v8[4] = 14; *(_DWORD *)&v8[8] = 13; *(_DWORD *)&v8[12] = 14; *(_DWORD *)&v8[16] = 4; *(_DWORD *)&v8[20] = 0; *(_DWORD *)&v8[24] = 0; *(_DWORD *)&v8[28] = 16; *(_DWORD *)&v8[32] = 5; *(_DWORD *)&v8[36] = 0; *(_DWORD *)&v8[40] = 0; *(_DWORD *)&v8[44] = 3; *(_DWORD *)&v8[48] = 5; *(_DWORD *)&v8[52] = 16; *(_DWORD *)&v8[56] = 14; *(_DWORD *)&v8[60] = 16; sub_DC2140((__m128i *)v5, 0, 0x40u); *(_DWORD *)v6 = 222105; *(_DWORD *)&v6[4] = 494358; *(_DWORD *)&v6[8] = 443201; *(_DWORD *)&v6[12] = 423901; *(_DWORD *)&v6[16] = 310311; *(_DWORD *)&v6[20] = 700114; *(_DWORD *)&v6[24] = 629640; *(_DWORD *)&v6[28] = 620483; *(_DWORD *)&v6[32] = 301566; *(_DWORD *)&v6[36] = 676368; *(_DWORD *)&v6[40] = 606711; *(_DWORD *)&v6[44] = 605590; *(_DWORD *)&v6[48] = 149250; *(_DWORD *)&v6[52] = 339264; *(_DWORD *)&v6[56] = 304846; *(_DWORD *)&v6[60] = 301296; if ( strlen(sn) != 16 ) return 0; for ( i = 0; i < 16; ++i ) { if ( (sn[i] < 48 || sn[i] > 57) && (sn[i] < 65 || sn[i] > 70) ) return 0; } for ( i = 0; i < 8; ++i ) { if ( sn[i] < 48 || sn[i] > 57 ) *(_DWORD *)sn1 += (sn[i] - 55) << (28 - 4 * i); else *(_DWORD *)sn1 += (sn[i] - 48) << (28 - 4 * i); if ( sn[i + 8] < 48 || sn[i + 8] > 57 ) *(_DWORD *)&sn1[4] += (sn[i + 8] - 55) << (28 - 4 * i); else *(_DWORD *)&sn1[4] += (sn[i + 8] - 48) << (28 - 4 * i); } sub_D31C70( sn1, aOneShallStandA, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, &v8[192], 0xDEADBEEF); sub_D93120(); return *(_DWORD *)sn1 == 0x87654321 && *(_DWORD *)&sn1[4] == 0x12345678; }
1、前面一大堆初始化的数据没啥用。
2、判断sn长度不等16则返回0
3、判断sn 是否是 0-9 A-F,不是返回0
4、将输入的字符串转换成2个int整数。
5、然后调用压入了貌似各种加密算法的数据以及一个字符串"One shall stand and one shall fall",不是你死就是我亡。
6、这些数据有的像MD5,有的像SM3,各种算法;
7、调用sub_D31C70
8、然后判断sn1 == 0x87654321 sn2 == 0x12345678,如果相等,则返回真。因此
sub_D31C70会将sn加密。
BOOL __cdecl check(char *sn) { char sn1[8]; // [esp+10h] [ebp-1D0h] int i; // [esp+18h] [ebp-1C8h] char v5[64]; // [esp+1Ch] [ebp-1C4h] char v6[64]; // [esp+5Ch] [ebp-184h] char v7[64]; // [esp+9Ch] [ebp-144h] char v8[256]; // [esp+DCh] [ebp-104h] *(_DWORD *)sn1 = 0; *(_DWORD *)&sn1[4] = 0; sub_DC2140((__m128i *)v7, 0, 0x40u); *(_DWORD *)v8 = 0; *(_DWORD *)&v8[196] = 0; *(_DWORD *)&v8[200] = 0; *(_DWORD *)&v8[204] = 0; *(_DWORD *)&v8[208] = 10; *(_DWORD *)&v8[212] = 15; *(_DWORD *)&v8[216] = 2; *(_DWORD *)&v8[220] = 13; *(_DWORD *)&v8[224] = 10; *(_DWORD *)&v8[228] = 8; *(_DWORD *)&v8[232] = 6; *(_DWORD *)&v8[236] = 15; *(_DWORD *)&v8[240] = 0; *(_DWORD *)&v8[244] = 5; *(_DWORD *)&v8[248] = 3; *(_DWORD *)&v8[252] = 0; *(_DWORD *)&v8[128] = 16; *(_DWORD *)&v8[132] = 0; *(_DWORD *)&v8[136] = 16; *(_DWORD *)&v8[140] = 14; *(_DWORD *)&v8[144] = 3; *(_DWORD *)&v8[148] = 10; *(_DWORD *)&v8[152] = 6; *(_DWORD *)&v8[156] = 0; *(_DWORD *)&v8[160] = 0; *(_DWORD *)&v8[164] = 7; *(_DWORD *)&v8[168] = 13; *(_DWORD *)&v8[172] = 6; *(_DWORD *)&v8[176] = 4; *(_DWORD *)&v8[180] = 7; *(_DWORD *)&v8[184] = 0; *(_DWORD *)&v8[188] = 2; *(_DWORD *)&v8[64] = 6; *(_DWORD *)&v8[68] = 16; *(_DWORD *)&v8[72] = 0; *(_DWORD *)&v8[76] = 12; *(_DWORD *)&v8[80] = 0; *(_DWORD *)&v8[84] = 11; *(_DWORD *)&v8[88] = 16; *(_DWORD *)&v8[92] = 12; *(_DWORD *)&v8[96] = 8; *(_DWORD *)&v8[100] = 12; *(_DWORD *)&v8[104] = 12; *(_DWORD *)&v8[108] = 0; *(_DWORD *)&v8[112] = 6; *(_DWORD *)&v8[116] = 0; *(_DWORD *)&v8[120] = 11; *(_DWORD *)&v8[124] = 13; *(_DWORD *)v8 = 16; *(_DWORD *)&v8[4] = 14; *(_DWORD *)&v8[8] = 13; *(_DWORD *)&v8[12] = 14; *(_DWORD *)&v8[16] = 4; *(_DWORD *)&v8[20] = 0; *(_DWORD *)&v8[24] = 0; *(_DWORD *)&v8[28] = 16; *(_DWORD *)&v8[32] = 5; *(_DWORD *)&v8[36] = 0; *(_DWORD *)&v8[40] = 0; *(_DWORD *)&v8[44] = 3; *(_DWORD *)&v8[48] = 5; *(_DWORD *)&v8[52] = 16; *(_DWORD *)&v8[56] = 14; *(_DWORD *)&v8[60] = 16; sub_DC2140((__m128i *)v5, 0, 0x40u); *(_DWORD *)v6 = 222105; *(_DWORD *)&v6[4] = 494358; *(_DWORD *)&v6[8] = 443201; *(_DWORD *)&v6[12] = 423901; *(_DWORD *)&v6[16] = 310311; *(_DWORD *)&v6[20] = 700114; *(_DWORD *)&v6[24] = 629640; *(_DWORD *)&v6[28] = 620483; *(_DWORD *)&v6[32] = 301566; *(_DWORD *)&v6[36] = 676368; *(_DWORD *)&v6[40] = 606711; *(_DWORD *)&v6[44] = 605590; *(_DWORD *)&v6[48] = 149250; *(_DWORD *)&v6[52] = 339264; *(_DWORD *)&v6[56] = 304846; *(_DWORD *)&v6[60] = 301296; if ( strlen(sn) != 16 ) return 0; for ( i = 0; i < 16; ++i ) { if ( (sn[i] < 48 || sn[i] > 57) && (sn[i] < 65 || sn[i] > 70) ) return 0; } for ( i = 0; i < 8; ++i ) { if ( sn[i] < 48 || sn[i] > 57 ) *(_DWORD *)sn1 += (sn[i] - 55) << (28 - 4 * i); else *(_DWORD *)sn1 += (sn[i] - 48) << (28 - 4 * i); if ( sn[i + 8] < 48 || sn[i + 8] > 57 ) *(_DWORD *)&sn1[4] += (sn[i + 8] - 55) << (28 - 4 * i); else *(_DWORD *)&sn1[4] += (sn[i + 8] - 48) << (28 - 4 * i); } sub_D31C70( sn1, aOneShallStandA, 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0x7380166F, 0x4914B2B9, 0x172442D7, 0xDA8A0600, &v8[192], 0xDEADBEEF); sub_D93120(); return *(_DWORD *)sn1 == 0x87654321 && *(_DWORD *)&sn1[4] == 0x12345678; }
1、前面一大堆初始化的数据没啥用。
2、判断sn长度不等16则返回0
3、判断sn 是否是 0-9 A-F,不是返回0
4、将输入的字符串转换成2个int整数。
5、然后调用压入了貌似各种加密算法的数据以及一个字符串"One shall stand and one shall fall",不是你死就是我亡。
6、这些数据有的像MD5,有的像SM3,各种算法;
7、调用sub_D31C70
8、然后判断sn1 == 0x87654321 sn2 == 0x12345678,如果相等,则返回真。因此
sub_D31C70会将sn加密。
四、
sub_D31C70加密函数
(一)垃圾指令与SMC
1、进去这个函数好大,
将近40K ,IDA没法识别。各种垃圾指令,而且还存在SMC,自修改代码。但是稍微分析下这些垃圾指令还是有规律的,比如:
;取出参数局部变量. text:00D31C91 BF 77 88 8C 60 mov edi, 608C8877h .text:00D31C96 81 EF A9 A3 67 D3 sub edi, 0D367A3A9h .text:00D31C9C 81 EF 61 55 D2 99 sub edi, 99D25561h .text:00D31CA2 81 EF 39 16 BF F8 sub edi, 0F8BF1639h .text:00D31CA8 81 EF 03 5E 7B 5E sub edi, 5E7B5E03h .text:00D31CAE 8B 8C FD 8C 26 3F 1F mov ecx, [ebp+edi*8+1F3F268Ch] ; sn1
;取出参数局部变量. text:00D31C91 BF 77 88 8C 60 mov edi, 608C8877h .text:00D31C96 81 EF A9 A3 67 D3 sub edi, 0D367A3A9h .text:00D31C9C 81 EF 61 55 D2 99 sub edi, 99D25561h .text:00D31CA2 81 EF 39 16 BF F8 sub edi, 0F8BF1639h .text:00D31CA8 81 EF 03 5E 7B 5E sub edi, 5E7B5E03h .text:00D31CAE 8B 8C FD 8C 26 3F 1F mov ecx, [ebp+edi*8+1F3F268Ch] ; sn1
2、SMC自修改代码
push eax
----------
push ebx
-----------
push ecx
一直到
pop ecx
pop ebx
pop eax
pop ecx
pop ebx
pop eax
代码解密结束。
.text:00D31F3B 50 push eax .text:00D31F3C 83 C9 00 or ecx, 0 .text:00D31F3F FC cld .text:00D31F40 53 push ebx .text:00D31F41 FC cld .text:00D31F42 F5 cmc .text:00D31F43 51 push ecx .text:00D31F44 85 F8 test eax, edi .text:00D31F46 90 nop .text:00D31F47 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31F4D 39 EB cmp ebx, ebp .text:00D31F4F 83 E1 FF and ecx, 0FFFFFFFFh .text:00D31F52 8B 40 30 mov eax, [eax+30h] .text:00D31F55 F7 C3 2C 0B EE 23 test ebx, 23EE0B2Ch .text:00D31F5B F5 cmc .text:00D31F5C 0F B6 40 02 movzx eax, byte ptr [eax+2] .text:00D31F60 90 nop .text:00D31F61 81 FD 84 48 6F 2D cmp ebp, 2D6F4884h .text:00D31F67 BB 00 00 00 00 mov ebx, 0 .text:00D31F6C .text:00D31F6C loc_D31F6C: ; CODE XREF: .text:00D31F7D↓j .text:00D31F6C 43 inc ebx .text:00D31F6D 39 C7 cmp edi, eax .text:00D31F6F F9 stc .text:00D31F70 83 C3 01 add ebx, 1 .text:00D31F73 F5 cmc .text:00D31F74 85 55 9C test [ebp-64h], edx .text:00D31F77 81 FB DA 94 0E 00 cmp ebx, 0E94DAh .text:00D31F7D 72 ED jb short loc_D31F6C .text:00D31F7F E8 00 00 00 00 call $+5 .text:00D31F84 5E pop esi .text:00D31F85 01 C6 add esi, eax .text:00D31F87 81 C6 70 E5 6C 88 add esi, 886CE570h .text:00D31F8D 81 C6 D6 30 78 14 add esi, 147830D6h .text:00D31F93 81 C6 08 55 23 93 add esi, 93235508h .text:00D31F99 81 C6 29 52 56 EB add esi, 0EB565229h .text:00D31F9F 81 C6 C0 42 A1 E4 add esi, 0E4A142C0h .text:00D31FA5 FF E6 jmp esi .text:00D31FA5 ; --------------------------------------------------------------------------- .text:00D31FA7 2B db 2Bh ; + .text:00D31FA8 ; --------------------------------------------------------------------------- .text:00D31FA8 55 push ebp .text:00D31FA9 1C 8B sbb al, 8Bh .text:00D31FAB 55 push ebp .text:00D31FAC F8 clc .text:00D31FAD 03 55 F4 add edx, [ebp-0Ch] .text:00D31FB0 8B 55 FC mov edx, [ebp-4] .text:00D31FB3 C1 E2 04 shl edx, 4 .text:00D31FB6 31 D0 xor eax, edx .text:00D31FB8 C1 E0 05 shl eax, 5 .text:00D31FBB B9 C4 00 00 00 mov ecx, 0C4h .text:00D31FC0 E8 00 00 00 00 call $+5 .text:00D31FC5 58 pop eax .text:00D31FC6 83 C0 71 add eax, 71h .text:00D31FC9 83 E8 0B sub eax, 0Bh .text:00D31FCC 32 08 xor cl, [eax] .text:00D31FCE 83 E8 0E sub eax, 0Eh .text:00D31FD1 02 08 add cl, [eax] .text:00D31FD3 83 E8 09 sub eax, 9 .text:00D31FD6 32 08 xor cl, [eax] .text:00D31FD8 83 E8 0E sub eax, 0Eh .text:00D31FDB 02 08 add cl, [eax] .text:00D31FDD 83 E8 0A sub eax, 0Ah .text:00D31FE0 32 08 xor cl, [eax] .text:00D31FE2 83 E8 09 sub eax, 9 .text:00D31FE5 32 08 xor cl, [eax] .text:00D31FE7 83 E8 0C sub eax, 0Ch .text:00D31FEA 2A 08 sub cl, [eax] .text:00D31FEC 83 E8 0B sub eax, 0Bh .text:00D31FEF 02 08 add cl, [eax] .text:00D31FF1 83 E8 0B sub eax, 0Bh .text:00D31FF4 02 08 add cl, [eax] .text:00D31FF6 83 E8 08 sub eax, 8 .text:00D31FF9 2A 08 sub cl, [eax] .text:00D31FFB E8 00 00 00 00 call $+5 .text:00D32000 58 pop eax .text:00D32001 83 C0 36 add eax, 36h .text:00D32004 83 C0 0B add eax, 0Bh .text:00D32007 28 08 sub [eax], cl .text:00D32009 83 C0 0B add eax, 0Bh .text:00D3200C 28 08 sub [eax], cl .text:00D3200E 83 C0 07 add eax, 7 .text:00D32011 30 08 xor [eax], cl .text:00D32013 83 C0 0C add eax, 0Ch .text:00D32016 28 08 sub [eax], cl .text:00D32018 83 C0 07 add eax, 7 .text:00D3201B 30 08 xor [eax], cl .text:00D3201D 83 C0 0F add eax, 0Fh .text:00D32020 30 08 xor [eax], cl .text:00D32022 83 C0 09 add eax, 9 .text:00D32025 00 08 add [eax], cl .text:00D32027 83 C0 0C add eax, 0Ch .text:00D3202A 00 08 add [eax], cl .text:00D3202C 83 C0 07 add eax, 7 .text:00D3202F 00 08 add [eax], cl .text:00D32031 83 C0 09 add eax, 9 .text:00D32034 28 08 sub [eax], cl .text:00D32036 59 pop ecx .text:00D32037 5B pop ebx .text:00D32038 58 pop eax
.text:00D31F3B 50 push eax .text:00D31F3C 83 C9 00 or ecx, 0 .text:00D31F3F FC cld .text:00D31F40 53 push ebx .text:00D31F41 FC cld .text:00D31F42 F5 cmc .text:00D31F43 51 push ecx .text:00D31F44 85 F8 test eax, edi .text:00D31F46 90 nop .text:00D31F47 64 A1 18 00 00 00 mov eax, large fs:18h .text:00D31F4D 39 EB cmp ebx, ebp .text:00D31F4F 83 E1 FF and ecx, 0FFFFFFFFh .text:00D31F52 8B 40 30 mov eax, [eax+30h] .text:00D31F55 F7 C3 2C 0B EE 23 test ebx, 23EE0B2Ch .text:00D31F5B F5 cmc .text:00D31F5C 0F B6 40 02 movzx eax, byte ptr [eax+2] .text:00D31F60 90 nop .text:00D31F61 81 FD 84 48 6F 2D cmp ebp, 2D6F4884h .text:00D31F67 BB 00 00 00 00 mov ebx, 0 .text:00D31F6C .text:00D31F6C loc_D31F6C: ; CODE XREF: .text:00D31F7D↓j .text:00D31F6C 43 inc ebx .text:00D31F6D 39 C7 cmp edi, eax .text:00D31F6F F9 stc .text:00D31F70 83 C3 01 add ebx, 1 .text:00D31F73 F5 cmc .text:00D31F74 85 55 9C test [ebp-64h], edx .text:00D31F77 81 FB DA 94 0E 00 cmp ebx, 0E94DAh .text:00D31F7D 72 ED jb short loc_D31F6C .text:00D31F7F E8 00 00 00 00 call $+5 .text:00D31F84 5E pop esi .text:00D31F85 01 C6 add esi, eax .text:00D31F87 81 C6 70 E5 6C 88 add esi, 886CE570h .text:00D31F8D 81 C6 D6 30 78 14 add esi, 147830D6h .text:00D31F93 81 C6 08 55 23 93 add esi, 93235508h .text:00D31F99 81 C6 29 52 56 EB add esi, 0EB565229h .text:00D31F9F 81 C6 C0 42 A1 E4 add esi, 0E4A142C0h .text:00D31FA5 FF E6 jmp esi .text:00D31FA5 ; --------------------------------------------------------------------------- .text:00D31FA7 2B db 2Bh ; + .text:00D31FA8 ; --------------------------------------------------------------------------- .text:00D31FA8 55 push ebp .text:00D31FA9 1C 8B sbb al, 8Bh .text:00D31FAB 55 push ebp .text:00D31FAC F8 clc .text:00D31FAD 03 55 F4 add edx, [ebp-0Ch] .text:00D31FB0 8B 55 FC mov edx, [ebp-4] .text:00D31FB3 C1 E2 04 shl edx, 4 .text:00D31FB6 31 D0 xor eax, edx .text:00D31FB8 C1 E0 05 shl eax, 5 .text:00D31FBB B9 C4 00 00 00 mov ecx, 0C4h .text:00D31FC0 E8 00 00 00 00 call $+5 .text:00D31FC5 58 pop eax .text:00D31FC6 83 C0 71 add eax, 71h .text:00D31FC9 83 E8 0B sub eax, 0Bh .text:00D31FCC 32 08 xor cl, [eax] .text:00D31FCE 83 E8 0E sub eax, 0Eh .text:00D31FD1 02 08 add cl, [eax] .text:00D31FD3 83 E8 09 sub eax, 9 .text:00D31FD6 32 08 xor cl, [eax] .text:00D31FD8 83 E8 0E sub eax, 0Eh .text:00D31FDB 02 08 add cl, [eax] .text:00D31FDD 83 E8 0A sub eax, 0Ah .text:00D31FE0 32 08 xor cl, [eax] .text:00D31FE2 83 E8 09 sub eax, 9 .text:00D31FE5 32 08 xor cl, [eax] .text:00D31FE7 83 E8 0C sub eax, 0Ch .text:00D31FEA 2A 08 sub cl, [eax] .text:00D31FEC 83 E8 0B sub eax, 0Bh .text:00D31FEF 02 08 add cl, [eax] .text:00D31FF1 83 E8 0B sub eax, 0Bh .text:00D31FF4 02 08 add cl, [eax] .text:00D31FF6 83 E8 08 sub eax, 8 .text:00D31FF9 2A 08 sub cl, [eax] .text:00D31FFB E8 00 00 00 00 call $+5 .text:00D32000 58 pop eax .text:00D32001 83 C0 36 add eax, 36h .text:00D32004 83 C0 0B add eax, 0Bh .text:00D32007 28 08 sub [eax], cl .text:00D32009 83 C0 0B add eax, 0Bh .text:00D3200C 28 08 sub [eax], cl .text:00D3200E 83 C0 07 add eax, 7 .text:00D32011 30 08 xor [eax], cl .text:00D32013 83 C0 0C add eax, 0Ch .text:00D32016 28 08 sub [eax], cl .text:00D32018 83 C0 07 add eax, 7 .text:00D3201B 30 08 xor [eax], cl .text:00D3201D 83 C0 0F add eax, 0Fh .text:00D32020 30 08 xor [eax], cl .text:00D32022 83 C0 09 add eax, 9 .text:00D32025 00 08 add [eax], cl .text:00D32027 83 C0 0C add eax, 0Ch .text:00D3202A 00 08 add [eax], cl .text:00D3202C 83 C0 07 add eax, 7 .text:00D3202F 00 08 add [eax], cl .text:00D32031 83 C0 09 add eax, 9 .text:00D32034 28 08 sub [eax], cl .text:00D32036 59 pop ecx .text:00D32037 5B pop ebx .text:00D32038 58 pop eax
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2018-12-9 14:00
被oooAooo编辑
,原因:
赞赏记录
参与人
雪币
留言
时间
一笑人间万事
为你点赞~
2022-7-27 01:53
心游尘世外
为你点赞~
2022-7-26 23:51
DCO
为你点赞~
2018-12-9 19:26
Editor
为你点赞~
2018-12-9 18:08
赞赏
他的文章
- 看雪CTF 2019总决赛 第六题 三道八佛 IDA脱壳脚本 5668
- [原创]看雪CTF2019Q3第四题WP 5933
- [原创]看雪CTF2019Q3 第二题WP 6760
- [2019看雪CTF晋级赛Q3第九题WP 12490
- [原创]看雪CTF2019晋级赛Q2第三题 5021
看原图
赞赏
雪币:
留言: