原页面
http://www.crackmes.de/users/malfunction/digital_arithmetic/
断断续续花了4天时间分析完了,XX的,对函数的处理比较全面完整,虽然简单,但是烦,很烦,分析比较麻烦,不过对跟踪的影响不极大.
本只想搞个简单的爆破,没料到卡飞了,放进killhim后前两2天还是累的时候轻松看看。
昨天稍微深入被函数压缩搞的心烦意乱,今个饭毕后暴走往完搞了.简单简单,权当练手.完整的分析了
整理分析出的东西弄个key花了2、3小时,总结出文章却搞到凌晨了,XX,该写个自动复制注释语句并合理链接的东西
在OD里面载入到函数里面比较麻烦,分析的是复制出来的一堆code,吐口气赞赞OD跳转指引和enter的好处,快刀斩乱麻这种简单的干扰
顺便,自己写code和逆向的区别在于一个是符号比标示符多,一个是标示符比符号多.
基本上每个调用都会
xchg [&API],eax;cmp byte ptr [eax], 0xcc;je over;xchg [&API],eax;
注意修改,不然卡蹦
每个proc都会处理,极度繁琐
主要有2种花
call ????;直接类似jmp修改解码流程
call ????;
qqqqq
bbbbbb
????:
call ????;
ssssssss
eeeeeeeeee
????:
call ???
前面2个call是入参用的,qqqqbbbb、ssssseeee即为call ???的参数
利用name 作为跳转表的索引,这样name错误时就执行到invalid name code了
一些cmp用sub xxx,0; add xxx,0代替
典型的编译器优化后加减法lea xxx,[yyy+-zzzz],再有很多糟蹋性能的code,自己猜测该是因为大量使用了宏处理。
进入就是乱糟糟的,loopd循环0x401000开始的0x23dd数据安装字节异或0x9a
接下来跳转到前面一点点;异或code,该是asm编的
00403376 FC CLD
00403377 E8 88DCFFFF CALL digital_.00401004 ; 载入库,初始化函数
401004里面是这种格式的循环
jmp xxxx;
return:
dd 0x0;
address:
dd size;
argc:
db size dup ??;
xxxx:
mov esi,address
lodsd
mov ecx,eax
mov edi,esi;
read:
test ecx,ecx;
JE finshed;
LODS BYTE PTR DS:[ESI]
XOR AL,44;address+4指定地址,size指定大小,字节异或0x44
STOS BYTE PTR ES:[EDI]
DEC ECX
JMP read;
finshed:
push argc;此处是压参,而非只一个push
xchg [&API],eax
cmp byte ptr [eax], 0xcc;检测int3断点
je over
xchg [&API],eax
call API
mov return,eax;
其中API为LoadLibraryA或GetProcAddress.参数即为argc,GetProcAddress会压入LoadLibraryA的return
over处一个rep把空间中所有数据清空,可直接把所有jmp over的跳转替换为无效指令
0x401004结束后所有GetProcAddress的return中就保存了argc中那名称API的地址
return序列即为IMT
接下来空参数调用COMDLG32.GetOpenFileNameA,这样除了设置了lasterror无任何作用
然后是USER32.DialogBoxParamA,窗口过程为40256C
最后直接ExitProcess
窗口过程中只处理
INITDIALOG
COMMAND
CLOSE 3个消息
过程分别为:
得到本进程handle、LoadIcon、SendMessage(SETICON)、GetDlgItem(NameOfkeyFile)、SendMessage(LIMITTEXT,hwnd=GetDlgItem)
单击Browse则调用0x401718;单击OK则调用0x40268f,返回值不能为FALSE(NULL),TURE则越过EndDialog;
EndDialog
0x40268f和0x401718类似,均为一个检测调试器的router
首先解码一data,然后调用一个设置返回地址为异常处理过程后除零的proc,若被调试则异常过程里面的code无法运行,即破坏了堆栈无法正常执行;后面的跳转,若ecx为0,则运行到错误的opcode,不然返回去循环解码:
0040269B 60 PUSHAD;异常和int3断点检测code开始.
00401719 BE 15194000 MOV ESI,digital_.00401915;需被解码code的结尾地址
0040171E B9 85010000 MOV ECX,185;大小
00401723 8B15 9A194000 MOV EDX,DWORD PTR DS:[40199A]
00401729 BF 94194000 MOV EDI,digital_.00401994;此处为解码code所用数据的结尾地址
0040172E BB 7D020000 MOV EBX,27D;所用数据大小,
;注意大小刚好到前面那个pushad
;这样不能在这段code中下int3断点,会解出乱码
PS:把2个合在一起,只为说明二个router是类似的
004026B6 0FB607 MOVZX EAX,BYTE PTR DS:[EDI]
004026B9 31C2 XOR EDX,EAX
004026BB 29C2 SUB EDX,EAX
004026BD 4F DEC EDI
004026BE 4B DEC EBX
004026BF 85DB TEST EBX,EBX
004026C1 ^ 75 F3 JNZ SHORT digital_.004026B6
004026C3 8B06 MOV EAX,DWORD PTR DS:[ESI]
004026C5 29D0 SUB EAX,EDX
004026C7 31D0 XOR EAX,EDX
004026C9 8906 MOV DWORD PTR DS:[ESI],EAX
这儿用call代替跳转+修改异常处理返回地址来检测调试器:
004026CB E8 24000000 CALL digital_.004026F4
004026D0 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C];esp+c指向上一个异常处理过程
004026D4 C782 B8000000 0>MOV DWORD PTR DS:[EDX+B8],digital_.0x402706>;[[esp+c]+0xb8]为触发异常地址,修改返回地址
004026DE C742 18 5501000>MOV DWORD PTR DS:[EDX+18],155;不了解的
004026E5 29C0 SUB EAX,EAX
004026E7 8942 04 MOV DWORD PTR DS:[EDX+4],EAX
004026EA 8942 08 MOV DWORD PTR DS:[EDX+8],EAX
004026ED 8942 0C MOV DWORD PTR DS:[EDX+C],EAX
004026F0 8942 10 MOV DWORD PTR DS:[EDX+10],EAX
004026F3 C3 RETN
004026F4 64:FF35 0000000>PUSH DWORD PTR FS:[0]
004026FB 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00402702 31C0 XOR EAX,EAX
00402704 F7F0 DIV EAX;不知为何"忽略除零"后硬件断点无法断在解码完成执行时,简单方法是在KiUserExceptionDispatcher 下条件断点判断ecx.得在Dispatcher第一个指令下断: mov ecx, [esp + 4];hmm,还有个法子,因为被压缩函数要用的数据需要初始化,若破坏执行流程则函数就会在执行过程中异常,这个异常就可以断下来了,更简单的ctrl + *;再可以阻止它穿裤子,清理了穿裤子的code
00402706 64:8F05 0000000>POP DWORD PTR FS:[0]
0040178A 83C4 04 ADD ESP,4
0040178D 4E DEC ESI
0040178E 49 DEC ECX;极其缓慢的解码
0040178F ^ 75 98 JNZ SHORT digital_.00401729;
连环2个
jnz
jnz
后面那个jnz跳转到的目标为乱码,而同时cpu对"75 ??"只解码其后的一bytes,简单的混淆。
前面的jnz用来循环解码,解码完后第二个jnz被覆盖了.
解压出来的数据起始为
00401A21 61 POPAD
00401A22 8F05 E31C4000 POP DWORD PTR DS:[40????] ;
pop的把返回地址送到目标指针
0040271B E8 05000000 CALL digital_.0040????
00402720 E9 5D020000 JMP digital_.0040????
call把下一指令地址压栈,这样函数结束时的retn就会返回到jmp.jmp跳到穿裤子code(压缩)
之后的router在结束时会再把数据压回去,即妨碍了执行一次程序流程然后附加进程直接看code
结束之后的retn是用一个重定向的跳转:
jmp [???????];????????处储存着重定向后的返回地址
注意上面那段是这个crackme频繁使用的proc和router的内部处理
PS:
补充下,Browse主要过程为
004018B4 FF15 BE164000 CALL NEAR DWORD PTR DS:[4016BE] ; COMDLG32.GetOpenFileNameA004018DC 50 PUSH EAX
004018DD 6A 66 PUSH 66; EditOfKeyFile
004018DF 53 PUSH EBX
004018E0 FF15 5E114000 CALL NEAR DWORD PTR DS:[40115E] ; USER32.SetDlgItemTextA
根据编码习惯推测一应检测都在"OK"过程中完成,故单刀直入 0x40268f router
保存下的code如下
0x40268f router:
00402714 61 POPAD;异常和int3断点检测code结束
00402715 8F05 0D2A4000 POP DWORD PTR DS:[402A0D] ; digital_.0040266B
0040271B E8 05000000 CALL digital_.00402725
00402720 E9 5D020000 JMP digital_.00402982
00402725 55 PUSH EBP; ok的消息router开始
00402726 89E5 MOV EBP,ESP
00402728 81EC BC000000 SUB ESP,0BC
0040272E FC CLD ;设置cld.可以认识为 按照c数组的格式来修改counter访问数据了
0040272F C785 50FFFFFF 0>MOV DWORD PTR SS:[EBP-B0],0 ; ebp - 0xb0 ,ret
00402739 8D45 DC LEA EAX,DWORD PTR SS:[EBP-24]; ebp-24 ,name buffer
0040273C 50 PUSH EAX
0040273D FF75 08 PUSH DWORD PTR SS:[EBP+8] ;hDlg
00402740 E8 51F8FFFF CALL digital_.00401F96 ;分析1 读取name
00402745 85C0 TEST EAX,EAX
00402747 0F84 2B020000 JE digital_.00402978; 0x402978为函数执行错误返回;
0040274D 8D85 48FFFFFF LEA EAX,DWORD PTR SS:[EBP-B8]; fileSizes
00402753 8D9D 4CFFFFFF LEA EBX,DWORD PTR SS:[EBP-B4]; fileSizes/0xc
00402759 53 PUSH EBX
0040275A 50 PUSH EAX
0040275B FF75 08 PUSH DWORD PTR SS:[EBP+8] ;hDlg
0040275E E8 45F2FFFF CALL digital_.004019A8; 分析2 读取keyFile
00402763 85C0 TEST EAX,EAX
00402765 0F84 0D020000 JE digital_.00402978; 0x402978为函数执行错误返回
0040276B 8985 44FFFFFF MOV DWORD PTR SS:[EBP-BC],EAX; ebp - 0xbc, hMem
00402771 8B85 48FFFFFF MOV EAX,DWORD PTR SS:[EBP-B8]; ebp - 0xb8, fileSizes
00402777 83C0 40 ADD EAX,40
0040277A C1E8 03 SHR EAX,3
0040277D 83C0 04 ADD EAX,4
00402780 8985 58FFFFFF MOV DWORD PTR SS:[EBP-A8],EAX; ebp - 0xa8,((fileSizes + 0x40) >> 0x3 )+0x4;
00402786 8705 BB144000 XCHG DWORD PTR DS:[4014BB],EAX
0040278C 8038 CC CMP BYTE PTR DS:[EAX],0CC
0040278F 0F84 CB1D0000 JE digital_.00404560
00402795 8705 BB144000 XCHG DWORD PTR DS:[4014BB],EAX
0040279B 6A 04 PUSH 4
0040279D 68 00100000 PUSH 1000
004027A2 50 PUSH EAX ;用((fileSizes + 0x40) >> 0x3 )+0x4作为hSpace的size
004027A3 6A 00 PUSH 0
004027A5 FF15 BB144000 CALL NEAR DWORD PTR DS:[4014BB] ; kernel32.VirtualAlloc
004027AB 85C0 TEST EAX,EAX
004027AD 0F84 9D010000 JE digital_.00402950
004027B3 8985 54FFFFFF MOV DWORD PTR SS:[EBP-AC],EAX;//ebp - 0xac 申请到的空间地址hSpace
004027B9 FFB5 48FFFFFF PUSH DWORD PTR SS:[EBP-B8];fileSizes/0xc
004027BF FFB5 58FFFFFF PUSH DWORD PTR SS:[EBP-A8];((fileSizes + 0x40) >> 0x3 )+0x4;
004027C5 50 PUSH EAX
004027C6 FFB5 44FFFFFF PUSH DWORD PTR SS:[EBP-BC]; hMem
004027CC E8 10050000 CALL digital_.00402CE1 ;分析3 判断keyFile是否符合条件
004027D1 85C0 TEST EAX,EAX
004027D3 0F84 24010000 JE digital_.004028FD ;释放hMem和hSpace
004027D9 8705 11164000 XCHG DWORD PTR DS:[401611],EAX
004027DF 8038 CC CMP BYTE PTR DS:[EAX],0CC
004027E2 0F84 781D0000 JE digital_.00404560
004027E8 8705 11164000 XCHG DWORD PTR DS:[401611],EAX
004027EE FF15 11164000 CALL NEAR DWORD PTR DS:[401611] ; kernel32.IsDebuggerPresent,简单的判断
004027F4 85C0 TEST EAX,EAX
004027F6 0F85 641D0000 JNZ digital_.00404560
004027FC 8D45 DC LEA EAX,DWORD PTR SS:[EBP-24]; ebp - 0x24,name buffer
004027FF 50 PUSH EAX
00402800 E8 23070000 CALL digital_.00402F28 ; 分析5 初始化unknow ()中的随机子 *(0x401000)
00402805 8D85 64FFFFFF LEA EAX,DWORD PTR SS:[EBP-9C] ;要被使用的序列
0040280B 50 PUSH EAX
0040280C E8 4A080000 CALL digital_.0040305B ;分析6 初始化序列
00402811 8D45 84 LEA EAX,DWORD PTR SS:[EBP-7C] ;使用上面修改后的随即子初始化
00402814 50 PUSH EAX
00402815 E8 41080000 CALL digital_.0040305B
0040281A 8D45 A4 LEA EAX,DWORD PTR SS:[EBP-5C]
0040281D 50 PUSH EAX
0040281E E8 38080000 CALL digital_.0040305B ;隔0x20字节为一个起点.
00402823 B9 0A000000 MOV ECX,0A
00402828 51 PUSH ECX ;保护ecx
00402829 8D5D DC LEA EBX,DWORD PTR SS:[EBP-24] ;ebp - 0x24,name buffer
0040282C 8D85 5CFFFFFF LEA EAX,DWORD PTR SS:[EBP-A4] ;依据被处理后的name buffer被初始化的8个字节
00402832 50 PUSH EAX
00402833 53 PUSH EBX
00402834 E8 2D020000 CALL digital_.00402A66 ;分析7 ebp - 0xa4设置为一个 key?
00402839 8DB5 5CFFFFFF LEA ESI,DWORD PTR SS:[EBP-A4] ;依据被处理后的name buffer被初始化的8个字节
0040283F 8D85 64FFFFFF LEA EAX,DWORD PTR SS:[EBP-9C] ;被name buffer随即子初始化的序列起点
00402845 8D7D C4 LEA EDI,DWORD PTR SS:[EBP-3C] ;
00402848 57 PUSH EDI ;array2
00402849 50 PUSH EAX ;array1
0040284A 56 PUSH ESI ;array0
0040284B E8 97090000 CALL digital_.004031E7 ;分析8 根据序列array1和array0填充array2 ret.
00402850 8D75 C4 LEA ESI,DWORD PTR SS:[EBP-3C]
00402853 8D45 84 LEA EAX,DWORD PTR SS:[EBP-7C]
00402856 8D7D CC LEA EDI,DWORD PTR SS:[EBP-34]
00402859 57 PUSH EDI
0040285A 50 PUSH EAX
0040285B 56 PUSH ESI
0040285C E8 86090000 CALL digital_.004031E7 ;分析8
00402861 8D75 CC LEA ESI,DWORD PTR SS:[EBP-34]
00402864 8D45 A4 LEA EAX,DWORD PTR SS:[EBP-5C]
00402867 8D7D C4 LEA EDI,DWORD PTR SS:[EBP-3C]
0040286A 57 PUSH EDI
0040286B 50 PUSH EAX
0040286C 56 PUSH ESI
0040286D E8 75090000 CALL digital_.004031E7 ;分析8 ;利用前面初始化完成的数据确定ret序列
00402872 8D85 5CFFFFFF LEA EAX,DWORD PTR SS:[EBP-A4] ;8字节序列
00402878 8D55 D4 LEA EDX,DWORD PTR SS:[EBP-2C] ;在name buffer - 0x8
0040287B 52 PUSH EDX ;unknow
0040287C FFB5 54FFFFFF PUSH DWORD PTR SS:[EBP-AC] ;申请到的空间地址hSpace
00402882 FFB5 48FFFFFF PUSH DWORD PTR SS:[EBP-B8] ;fileSizes/0xc
00402888 FFB5 44FFFFFF PUSH DWORD PTR SS:[EBP-BC] ;hMem
0040288E 50 PUSH EAX ;Coverage
0040288F E8 53F4FFFF CALL digital_.00401CE7 ;分析9 判断ret序列是否符合条件
00402894 8D75 C4 LEA ESI,DWORD PTR SS:[EBP-3C] ;ret序列
00402897 8D7D D4 LEA EDI,DWORD PTR SS:[EBP-2C] ;分析9 unknow
0040289A B9 08000000 MOV ECX,8
0040289F F3:A6 REPE CMPS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI];
004028A1 59 POP ECX
004028A2 75 59 JNZ SHORT digital_.004028FD; 分析9 unknow必须ret序列中数据一致
004028A4 49 DEC ECX
004028A5 ^ 75 81 JNZ SHORT digital_.00402828;循环判断8次
004028A7 C785 50FFFFFF 0>MOV DWORD PTR SS:[EBP-B0],1 ; ret = TURE
004028B1 6A 40 PUSH 40
004028B3 E8 10000000 CALL digital_.004028C8 ; finshed
;-------------------下面是无效code:其实是数据,MessageBox的参数
004028B8 43 INC EBX
004028B9 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
004028BA 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
004028BB 67:72 61 JB SHORT digital_.0040291F ; 多余的前缀
004028BE 74 75 JE SHORT digital_.00402935
004028C0 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
004028C1 61 POPAD
004028C2 74 69 JE SHORT digital_.0040292D
004028C4 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
004028C5 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
004028C6 73 00 JNB SHORT digital_.004028C8
;------------------------
004028C8 E8 26000000 CALL digital_.004028F3
;----------------------下面是无效code
004028CD 43 INC EBX
004028CE 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
004028CF 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
004028D0 67:72 61 JB SHORT digital_.00402934 ; 多余的前缀
004028D3 74 75 JE SHORT digital_.0040294A
004028D5 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
004028D6 61 POPAD
004028D7 74 69 JE SHORT digital_.00402942
004028D9 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
004028DA 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
004028DB 73 21 JNB SHORT digital_.004028FE
004028DD 2059 6F AND BYTE PTR DS:[ECX+6F],BL
004028E0 75 72 JNZ SHORT digital_.00402954
004028E2 206B 65 AND BYTE PTR DS:[EBX+65],CH
004028E5 79 20 JNS SHORT digital_.00402907
004028E7 6973 20 636F727>IMUL ESI,DWORD PTR DS:[EBX+20],72726F>
004028EE 65:637421 00 ARPL WORD PTR GS:[ECX],SI
;---------------------
004028F3 6A 00 PUSH 0
004028F5 FF15 B8114000 CALL NEAR DWORD PTR DS:[4011B8] ; USER32.MessageBoxA
004028FB EB 2B JMP SHORT digital_.00402928
004028FD 6A 10 PUSH 10
004028FF E8 06000000 CALL digital_.0040290A;假call
;--------------------------下面的code无效
00402904 45 INC EBP
00402905 72 72 JB SHORT digital_.00402979
00402907 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
00402908 72 00 JB SHORT digital_.0040290A
;--------------------------------
0040290A E8 11000000 CALL digital_.00402920
;---------------------------------下面的code无效
0040290F 49 DEC ECX
00402910 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
00402911 76 61 JBE SHORT digital_.00402974
00402913 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
00402914 696420 6B 65796>IMUL ESP,DWORD PTR DS:[EAX+6B],696679>
0040291C 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
0040291D 65:2100 AND DWORD PTR GS:[EAX],EAX
;---------------------------------------
00402920 6A 00 PUSH 0
00402922 FF15 B8114000 CALL NEAR DWORD PTR DS:[4011B8] ; USER32.MessageBoxA
00402928 8705 12154000 XCHG DWORD PTR DS:[401512],EAX
0040292E 8038 CC CMP BYTE PTR DS:[EAX],0CC
00402931 0F84 291C0000 JE digital_.00404560
00402937 8705 12154000 XCHG DWORD PTR DS:[401512],EAX
0040293D 68 00800000 PUSH 8000
00402942 6A 00 PUSH 0
00402944 FFB5 54FFFFFF PUSH DWORD PTR SS:[EBP-AC] ;hSpace的释放
0040294A FF15 12154000 CALL NEAR DWORD PTR DS:[401512] ; kernel32.VirtualFree
00402950 8705 12154000 XCHG DWORD PTR DS:[401512],EAX
00402956 8038 CC CMP BYTE PTR DS:[EAX],0CC
00402959 0F84 011C0000 JE digital_.00404560
0040295F 8705 12154000 XCHG DWORD PTR DS:[401512],EAX
00402965 68 00800000 PUSH 8000
0040296A 6A 00 PUSH 0
0040296C FFB5 44FFFFFF PUSH DWORD PTR SS:[EBP-BC] ;hMem的释放
00402972 FF15 12154000 CALL NEAR DWORD PTR DS:[401512] ; kernel32.VirtualFree
00402978 8B85 50FFFFFF MOV EAX,DWORD PTR SS:[EBP-B0]; return ret;
0040297E C9 LEAVE
0040297F C2 0400 RETN 4;注意retn 4是为了平衡刚才的假call
--
00402982 60 PUSHAD; 包含异常并有int3断点检测code开始 PS:压缩code
00402983 BE 14274000 MOV ESI,digital_.00402714;起始地址
00402988 B9 6B020000 MOV ECX,26B;size
0040298D BA 6B528C5A MOV EDX,5A8C526B;这儿赋给edx的值是前面计算 所用数据得到的值;若这儿也是动态计算的,便可随便改解出code,因为会被正确的保存和读取。
00402992 8B06 MOV EAX,DWORD PTR DS:[ESI]
00402994 31D0 XOR EAX,EDX
00402996 01D0 ADD EAX,EDX
00402998 8906 MOV DWORD PTR DS:[ESI],EAX
0040299A BF 9B264000 MOV EDI,digital_.0040269B
0040299F BB 63030000 MOV EBX,363
004029A4 0FB607 MOVZX EAX,BYTE PTR DS:[EDI]
004029A7 01C2 ADD EDX,EAX
004029A9 31C2 XOR EDX,EAX
004029AB 47 INC EDI
004029AC 4B DEC EBX
004029AD 85DB TEST EBX,EBX
004029AF ^ 75 F3 JNZ SHORT digital_.004029A4
004029B1 E8 24000000 CALL digital_.004029DA;此处又是一个假call,类似于上面那router开首,不过这是解码反过来
004029B6 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
004029BA C782 B8000000 E>MOV DWORD PTR DS:[EDX+B8],digital_.0>
004029C4 C742 18 5501000>MOV DWORD PTR DS:[EDX+18],155
004029CB 29C0 SUB EAX,EAX
004029CD 8942 04 MOV DWORD PTR DS:[EDX+4],EAX
004029D0 8942 08 MOV DWORD PTR DS:[EDX+8],EAX
004029D3 8942 0C MOV DWORD PTR DS:[EDX+C],EAX
004029D6 8942 10 MOV DWORD PTR DS:[EDX+10],EAX
004029D9 C3 RETN
004029DA 64:FF35 0000000>PUSH DWORD PTR FS:[0]
004029E1 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
004029E8 31C0 XOR EAX,EAX
004029EA F7F0 DIV EAX;一样奇怪的需要shift+F9一次
004029EC 64:8F05 0000000>POP DWORD PTR FS:[0]
004029F3 83C4 04 ADD ESP,4
004029F6 46 INC ESI
004029F7 49 DEC ECX
004029F8 ^ 75 98 JNZ SHORT digital_.00402992
004029FA 8915 032A4000 MOV DWORD PTR DS:[402A03],EDX
004029FA 8915 032A4000 MOV DWORD PTR DS:[402A03],EDX
00402A00 61 POPAD;异常和int3断点检测code结束
00402A01 EB 04 JMP SHORT digital_.00402A07
00402A03 E1 3D LOOPDE SHORT digital_.00402A42
00402A05 FE ??? ; 未知命令
00402A06 5D POP EBP
00402A07 ^ FF25 0D2A4000 JMP NEAR DWORD PTR DS:[402A0D] ; digital_.00402725函数返回了
总结起来为
比较name是否valid,取得name放入 (ebp-24)[0x1f]序列 ,name buffer
比较keyFile是否可以载入,然后相关数据分别放入:
ebp - 0xbc, hMem;
EBP-B8,fileSizes
ebp - 0xb8, fileSizes/0xc;
ebp - 0xa8,((fileSizes + 0x40) >> 0x3 )+0x4;
以hMem, hSpace, ((fileSizes + 0x40) >> 0x3 )+0x4, fileSizes/0xc作为proc3(array0, array1, times, len)的参数,用文件大小来决定是否符合要求。同时hSpace会被依据hMem填充
以ebp - 0x24,name buffer为参数初始化unknow ()中的随即子
EBP-9C 至 EBP-3C 的数据被使用随即子初始化.
完成后进入一共8次的循环:
分析7利用初始化完成的数据初始化一个8字节序列.
分析8会利用初始化完成数据和8字节序列生成ret序列.
接着ret序列与分析9利用hSpace、Coverage(8字节序列)、hMem、Filesize/0xc生成的unknow序列比较,相同则下一次循环
完全符合要求时TURE返回.
digital_.00401F96被内部压缩了,直接帖出解压后的流程
分析1:
0040200F 61 POPAD
00402010 8F05 68214000 POP DWORD PTR DS:[402168] ; digital_.00402745
00402016 E8 05000000 CALL digital_.00402020
0040201B E9 BD000000 JMP digital_.004020DD
00402020 55 PUSH EBP
00402021 89E5 MOV EBP,ESP
00402023 8705 04114000 XCHG DWORD PTR DS:[401104],EAX
00402029 8038 CC CMP BYTE PTR DS:[EAX],0CC
0040202C 0F84 2E250000 JE digital_.00404560
00402032 8705 04114000 XCHG DWORD PTR DS:[401104],EAX
00402038 6A 21 PUSH 21
0040203A FF75 0C PUSH DWORD PTR SS:[EBP+C];name缓冲区
0040203D 6A 65 PUSH 65 ;EditOfName
0040203F FF75 08 PUSH DWORD PTR SS:[EBP+8] ;hDlg
00402042 FF15 04114000 CALL NEAR DWORD PTR DS:[401104] ; USER32.GetDlgItemTextA
00402048 85C0 TEST EAX,EAX;
0040204A 75 33 JNZ SHORT digital_.0040207F;没有失败时跳过去
0040204C 6A 10 PUSH 10
0040204E E8 06000000 CALL digital_.00402059
;---------------------下面的code无效
00402053 45 INC EBP
00402054 72 72 JB SHORT digital_.004020C8
00402056 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
00402057 72 00 JB SHORT digital_.00402059
;--------------------------------
00402059 E8 15000000 CALL digital_.00402073
;------------------------------下面的code无效
0040205E 50 PUSH EAX
0040205F 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
00402060 65:61 POPAD ; 多余的前缀
00402062 73 65 JNB SHORT digital_.004020C9
00402064 2065 6E AND BYTE PTR SS:[EBP+6E],AH
00402067 74 65 JE SHORT digital_.004020CE
00402069 72 20 JB SHORT digital_.0040208B
0040206B 61 POPAD
0040206C 206E 61 AND BYTE PTR DS:[ESI+61],CH
0040206F 6D INS DWORD PTR ES:[EDI],DX ; I/O 命令
00402070 65:2100 AND DWORD PTR GS:[EAX],EAX
;------------------------------------
00402073 6A 00 PUSH 0
00402075 FF15 B8114000 CALL NEAR DWORD PTR DS:[4011B8] ; USER32.MessageBoxA name太短
0040207B 31C0 XOR EAX,EAX
0040207D EB 5A JMP SHORT digital_.004020D9
0040207F 83F8 06 CMP EAX,6;正常时的流程
00402082 72 2B JB SHORT digital_.004020AF;name小于6字节则错误返回
00402084 50 PUSH EAX
00402085 FF75 0C PUSH DWORD PTR SS:[EBP+C];name缓冲区塞进0x401e5b处理
00402088 E8 CEFDFFFF CALL digital_.00401E5B; 分析10
0040208D B9 20000000 MOV ECX,20
00402092 31D2 XOR EDX,EDX
00402094 8B5D 0C MOV EBX,DWORD PTR SS:[EBP+C]
~~~~~~~~~~~~~
00402097 85C9 TEST ECX,ECX;
00402099 74 0D JE SHORT digital_.004020A8;20个字符比较完时可以正常返回
0040209B 49 DEC ECX
0040209C 0FB60413 MOVZX EAX,BYTE PTR DS:[EBX+EDX];ebx namebuffer,edx counter
004020A0 42 INC EDX;
004020A1 FF2485 6C214000 JMP NEAR DWORD PTR DS:[EAX*4+40216C];40216c处的跳转表附在结尾,若跳到4020af则invalid name
004020A8 B8 01000000 MOV EAX,1
004020AD EB 2A JMP SHORT digital_.004020D9;
~~~~~~~~~~~~~
004020AF 6A 10 PUSH 10;
004020B1 E8 06000000 CALL digital_.004020BC;invalid name
;---------------------------------------下面的code无效
004020B6 45 INC EBP
004020B7 72 72 JB SHORT digital_.0040212B
004020B9 6F OUTS DX,DWORD PTR ES:[EDI] ; I/O 命令
004020BA 72 00 JB SHORT digital_.004020BC
;----------------------------------------
004020BC E8 0E000000 CALL digital_.004020CF
;-------------------------------------------下面的code无效
004020C1 49 DEC ECX
004020C2 6E OUTS DX,BYTE PTR ES:[EDI] ; I/O 命令
004020C3 76 61 JBE SHORT digital_.00402126
004020C5 6C INS BYTE PTR ES:[EDI],DX ; I/O 命令
004020C6 696420 6E 616D6>IMUL ESP,DWORD PTR DS:[EAX+6E],21656D>
004020CE 006A 00 ADD BYTE PTR DS:[EDX],CH
;-----------------------------------------
;0x4020cf 6a00 push 0;
004020D1 FF15 B8114000 CALL NEAR DWORD PTR DS:[4011B8] ; USER32.MessageBoxA
004020D7 31C0 XOR EAX,EAX;返回FALSE
004020D9 C9 LEAVE ;跳转到此处为正常返回,eax = TURE;
004020DA C2 0800 RETN 8
-----
004020DD 60 PUSHAD;压缩
004020DE BE 0F204000 MOV ESI,digital_.0040200F
004020E3 B9 CB000000 MOV ECX,0CB
004020E8 BA 6B528C5A MOV EDX,5A8C526B
004020ED 8B06 MOV EAX,DWORD PTR DS:[ESI]
004020EF 31D0 XOR EAX,EDX
004020F1 01D0 ADD EAX,EDX
004020F3 8906 MOV DWORD PTR DS:[ESI],EAX
004020F5 BF 961F4000 MOV EDI,digital_.00401F96
004020FA BB C3010000 MOV EBX,1C3
004020FF 0FB607 MOVZX EAX,BYTE PTR DS:[EDI]
00402102 01C2 ADD EDX,EAX
00402104 31C2 XOR EDX,EAX
00402106 47 INC EDI
00402107 4B DEC EBX
00402108 85DB TEST EBX,EBX
0040210A ^ 75 F3 JNZ SHORT digital_.004020FF
0040210C E8 24000000 CALL digital_.00402135
00402111 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
00402115 C782 B8000000 4>MOV DWORD PTR DS:[EDX+B8],digital_.0>
0040211F C742 18 5501000>MOV DWORD PTR DS:[EDX+18],155
00402126 29C0 SUB EAX,EAX
00402128 8942 04 MOV DWORD PTR DS:[EDX+4],EAX
0040212B 8942 08 MOV DWORD PTR DS:[EDX+8],EAX
0040212E 8942 0C MOV DWORD PTR DS:[EDX+C],EAX
00402131 8942 10 MOV DWORD PTR DS:[EDX+10],EAX
00402134 C3 RETN
00402135 64:FF35 0000000>PUSH DWORD PTR FS:[0]
0040213C 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
00402143 31C0 XOR EAX,EAX
00402145 F7F0 DIV EAX
00402147 64:8F05 0000000>POP DWORD PTR FS:[0]
0040214E 83C4 04 ADD ESP,4
00402151 46 INC ESI
00402152 49 DEC ECX
00402153 ^ 75 98 JNZ SHORT digital_.004020ED
00402155 8915 5E214000 MOV DWORD PTR DS:[40215E],EDX
0040215B 61 POPAD
0040215C EB 04 JMP SHORT digital_.00402162
00402162 /FF25 68214000 JMP NEAR DWORD PTR DS:[402168] ; digital_.00402745,返回。402020函数结束
得到用户名,必须大于6byte。name长度为times,0x401e5b处理完name后,以name为case循环20次switch来判断是否valid.
name算法为
bool nameValid (int hDlg,char* name)
{
if ((len = USER32.GetDlgItemTextA)<6)
{
return FALSE;
}
0x401e5bproc (len, name);//分析10
int counter = 0;
while (counter++ < 20)
{
switch (name[counter]);//分析见下
}
}
name中的字符需符合
0x2b>char>0x28
0x30>char>0x2E
0x3b>char>0x31
.......
不能指向0x4020af
跳转表
0040216C ; 004020AF 004020AF 004020AF 004020AF
0040217C ; 004020AF 004020AF 004020AF 004020AF
0040218C ; 004020AF 004020AF 004020AF 004020AF
0040219C ; 004020AF 004020AF 004020AF 004020AF
004021AC ; 004020AF 004020AF 004020AF 004020AF
004021BC ; 004020AF 004020AF 004020AF 004020AF
004021CC ; 004020AF 004020AF 004020AF 004020AF
004021DC ; 004020AF 004020AF 004020AF 004020AF
004021EC ; 00402097 004020AF 004020AF 004020AF
004021FC ; 004020AF 004020AF 004020AF 004020AF
0040220C ; 00402097 00402097 004020AF 004020AF
0040221C ; 004020AF 00402097 00402097 004020AF
0040222C ; 00402097 00402097 00402097 00402097
0040223C ; 00402097 00402097 00402097 00402097
0040224C ; 00402097 00402097 004020AF 004020AF
0040225C ; 00402097 004020AF 00402097 004020AF
0040226C ; 004020AF 00402097 00402097 00402097
0040227C ; 00402097 00402097 00402097 00402097
0040228C ; 00402097 00402097 00402097 00402097
0040229C ; 00402097 00402097 00402097 00402097
004022ac ; 00402097 00402097 00402097 00402097
004022BC ; 00402097 00402097 00402097 00402097
004022CC ; 00402097 00402097 00402097 00402097
004022DC ; 004020AF 00402097 004020AF 004020AF
004022EC ; 004020AF 00402097 00402097 00402097
004022FC ; 00402097 00402097 00402097 00402097
0040230C ; 00402097 00402097 00402097 00402097
0040231C ; 00402097 00402097 00402097 00402097
0040232C ; 00402097 00402097 00402097 00402097
0040233C ; 00402097 00402097 00402097 00402097
0040234C ; 00402097 00402097 00402097 004020AF
0040235C ; 004020AF 004020AF 004020AF 004020AF
0040236C ; 004020AF 004020AF 004020AF 004020AF
0040237C ; 004020AF 004020AF 004020AF 004020AF
0040238C ; 004020AF 004020AF 004020AF 004020AF
0040239C ; 004020AF 004020AF 004020AF 004020AF
004023AC ; 004020AF 004020AF 004020AF 004020AF
004023BC ; 004020AF 004020AF 004020AF 004020AF
004023CC ; 004020AF 004020AF 004020AF 004020AF
004023DC ; 004020AF 004020AF 004020AF 004020AF
004023EC ; 004020AF 004020AF 004020AF 004020AF
004023FC ; 004020AF 004020AF 004020AF 004020AF
0040240C ; 004020AF 004020AF 004020AF 004020AF
0040241C ; 004020AF 004020AF 004020AF 004020AF
0040242C ; 004020AF 004020AF 004020AF 004020AF
0040243C ; 004020AF 004020AF 004020AF 004020AF
0040244C ; 004020AF 004020AF 004020AF 004020AF
0040245C ; 004020AF 004020AF 004020AF 004020AF
0040246C ; 004020AF 004020AF 004020AF 004020AF
0040247C ; 004020AF 004020AF 004020AF 004020AF
0040248C ; 004020AF 004020AF 004020AF 004020AF
0040249C ; 004020AF 004020AF 004020AF 004020AF
004024AC ; 004020AF 004020AF 004020AF 004020AF
004024BC ; 004020AF 004020AF 004020AF 004020AF
004024CC ; 004020AF 004020AF 004020AF 004020AF
004024DC ; 004020AF 004020AF 004020AF 004020AF
004024EC ; 004020AF 004020AF 004020AF 004020AF
004024FC ; 004020AF 004020AF 004020AF 004020AF
0040250C ; 004020AF 004020AF 004020AF 004020AF
0040251C ; 004020AF 004020AF 004020AF 004020AF
0040252C ; 004020AF 004020AF 004020AF 004020AF
0040253C ; 004020AF 004020AF 004020AF 004020AF
0040254C ; 004020AF 004020AF 004020AF 004020AF
0040255C ; 004020AF 004020AF 004020AF 004020AF
一个就显得长了,分析1-10放在附件
可用用户名和keyFile实在是懒得做了,权当是resever me了一把
文件size必须为0xc的倍数.
每个双字都必须大于size/0xc + 0x40
文件大小第一轮判断:
文件每个0xc bytes中第三个双字除以32后作为x,hSpace[x]被双子&0x1f后得到的位设置位.同时第二次设置hSpace中同一个位(hSpace的大小为文件size/0xc)
同时hSpace序列开始2个int必须初始化为NULL
若(size/0xc)&0x1f不为空,则1000 0000 0000 0000 0000 0000 0000 0000b算术右移 (len & 0x1f) -1,结果再循环右移 (len & 0x1f),hSpace序列的最后一位必须为位移结果。
第二轮:
hSpace前2个int 置0xffffffff,这限制了hMem中每0xc bytes中前2 int的取值
对于hMem,2个序列ebx、esi都指向开头,然后
每0xc bytes前2个int若符合hSpace[hMem[int] >> 0x5] | (hMem[int] & 0x1f)之后不设置任何值,则esi递增一组数据
前2 int未设置时任何位时int用hSpace[hMem[int] >> 0x5] | (hMem[int] & 0x1f)设置一位,然后判断ebx是否已经追上esi,是则递增esi一组数据,否则ebx指向的和esi指向的一组数据交换,并递增ebx一组数据
而最后处理完size/0xc组数据时,最后一个处理必须是esi的递增.
rand子的初始化是把0x20字节name buffer里8个int加到一起,这是rand子
name随机序列的初始化(0x9c-0x3c):
0x20字节一组.
前0x18个字节被初始化为"8765432187...."
每个0x8字节如下处理:
(((rand * 0x3f3fd + 0x269ec3) >> 0x10 ) & 0x7ffff) & 0x7得到一个数字,重复次再一个数字,这二数字指向的byte交换.注意rand是个全局变量,每次循环被赋值为(rand * 0x3f3fd + 0x269ec3)
前0x18个字节依次处理,循环0x64次
0x18后的0x8字节rand计算方式不变.使用方式,rand ((rand * 0x3f3fd + 0x269ec3) >> 0x10 )返回的数字mod 6然后 & 0xff得到一字节,从0-7依次循环置完.
3组name随机序列皆如此处理
然后是最后的判断,这段循环10次
初始化8字节数组并处理name buffer:
name buffer每个byte的处理,int temp加上前面的temp,然后取从尾部开始计量的2、3位(0开始计量)来作为后一个byte的值.temp 初始值为0xac
ebp - 0xa4的前8个字符被处理完name buffer序列的最后8字符 & 0xff后倒序覆盖.
分析9和结果已经在前面总结了,hmm.
菜人整理笔记的产物,有误就指正
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)