穿山甲小牛试刀之一+秒杀N层马甲之Nnewell的某KeyGenMe
【目 标】: Nnewell的某KeyGenMe
【工 具】:Olydbg1.1B(diy版)、LORDPE、ImportREC1.6F
【任 务】:.透视N层马甲(暴破),简单脱N层壳.
【操作平台】:winxp sp1
【作 者】:loveboom[DFCG][FCG]
【相关链接】: 见附件
【简要说明】:很久没有写什么文章,都快老了,我自己也终于结束了几年的网吧调试生活,就此献给所有的朋友,也算是献给男羽终于一次爬上TOP1的小礼吧,失误之处还请各位老大多多指教。我用Nnewell老大的东西出来骗一下MM,不知道老大有什么意见..如老大说不要这样的就我就删除本贴.
【详细过程】:
如果暴破来说,这个东西还是比较易的,牛老大说要写注册机,我水平没够所以就难一下,再说也没有空去分析算法。好了,搞定任务一.,透视N层马甲,再来强暴.
用od加载目标,去除调试标志.忽略全部异常。
加载并运行目标,这样第一次在这里异常:
042E137F 6285 0E0B0000 BOUND EAX,QWORD PTR SS:[EBP+B0E] ;这里异常
042E1385 EB 02 JMP SHORT 042E1389
异常后,shift+f9继续,这样程序就运行了,现在看看od里怎么什么也没有了,不用紧张,“上有政策,下有对策”嘛,程序运行后,我们按一下F12怎么样,OD里有东西了吧,按f12断下后,按F9让程序继续,这样会有一个异常的提示,注意了,点那个消息框后按shift+f9而不要按f9,因为这样的话,等一下就死的好看的。好了,操作完毕后,ALT+M打开内存页,看看code段的baseimg是多少,原来是401000,,现在回到od的cpu窗口中,按ctrl+G跳到401000那里(当然这一步不是必需的),到主程序的段里后下断bp GetWindowTextA
在目标里输入你的大名和注册码,然后点register,这样会断在这里:
77D17FEC > 6A 0C PUSH 0C ;断在这里
77D17FEE 68 309DD677 PUSH USER32.77D69D30
断下后,alt+f9执行到返回:
0040D917 FF15 AA374100 CALL DWORD PTR DS:[4137AA] ; 这里就是GetDlgItemTextA
0040D91D A3 4C364100 MOV DWORD PTR DS:[41364C],EAX ; 用户长度入地址,eax=用户名长度
0040D922 0BC0 OR EAX,EAX
0040D924 75 1F JNZ SHORT KeygenMe.0040D945 ; 如果用户不为空就跳
0040D926 6A 00 PUSH 0 ; 注册名为空就跳到这里,也就是over的路
0040D928 FF75 0C PUSH DWORD PTR SS:[EBP+C]
0040D92B FF75 10 PUSH DWORD PTR SS:[EBP+10]
0040D92E FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040D931 FF15 B0374100 CALL DWORD PTR DS:[4137B0] ; 这里就是MessageBoxA了
0040D937 5B POP EBX
0040D938 891D 5C364100 MOV DWORD PTR DS:[41365C],EBX
0040D93E 5F POP EDI
0040D93F 5E POP ESI
0040D940 5B POP EBX
0040D941 C9 LEAVE
0040D942 C2 1800 RETN 18
0040D945 68 00010000 PUSH 100 ; 这里准备获取注册码
0040D94A 8D85 D0FAFFFF LEA EAX,DWORD PTR SS:[EBP-530]
0040D950 50 PUSH EAX
0040D951 68 E9030000 PUSH 3E9 ; push id
0040D956 FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040D959 FF15 AA374100 CALL DWORD PTR DS:[4137AA] ; GetDlgItemTextA
0040D95F A3 50364100 MOV DWORD PTR DS:[413650],EAX ; 这里eax=注册码长度
0040D964 0BC0 OR EAX,EAX
0040D966 75 1F JNZ SHORT KeygenMe.0040D987 ; 如果注册码不为空就跳
0040D968 6A 00 PUSH 0 ; 为空就不好玩了,为空走这里
0040D96A FF75 0C PUSH DWORD PTR SS:[EBP+C]
0040D96D FF75 14 PUSH DWORD PTR SS:[EBP+14]
0040D970 FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040D973 FF15 B0374100 CALL DWORD PTR DS:[4137B0] ; KeygenMe.0040E79E
0040D979 5B POP EBX
0040D97A 891D 5C364100 MOV DWORD PTR DS:[41365C],EBX
0040D980 5F POP EDI
0040D981 5E POP ESI
0040D982 5B POP EBX
0040D983 C9 LEAVE
0040D984 C2 1800 RETN 18
0040D987 8D85 D0FAFFFF LEA EAX,DWORD PTR SS:[EBP-530]
0040D98D 50 PUSH EAX ; 注册码入栈
0040D98E E8 9D0D0000 CALL KeygenMe.0040E730 ; 这个call把注册码转换为大写
0040D993 E8 2E0C0000 CALL KeygenMe.0040E5C6 ;这里要小心,在下一行下断,因为这个call里什么东西都不做,N多次异常在里面
0040D998 8D85 D0FAFFFF LEA EAX,DWORD PTR SS:[EBP-530]
0040D99E 50 PUSH EAX
0040D99F E8 9A0C0000 CALL KeygenMe.0040E63E ; 这个call判断注册码的合法性
0040D9A4 83F8 01 CMP EAX,1
0040D9A7 75 1F JNZ SHORT KeygenMe.0040D9C8 ; 如果合法就跳
0040D9A9 6A 00 PUSH 0
0040D9AB FF75 0C PUSH DWORD PTR SS:[EBP+C] ; 不合法就出错信息
0040D9AE FF75 18 PUSH DWORD PTR SS:[EBP+18]
0040D9B1 FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040D9B4 FF15 B0374100 CALL DWORD PTR DS:[4137B0] ; KeygenMe.0040E79E
0040D9BA 5B POP EBX
0040D9BB 891D 5C364100 MOV DWORD PTR DS:[41365C],EBX
0040D9C1 5F POP EDI
0040D9C2 5E POP ESI
0040D9C3 5B POP EBX
0040D9C4 C9 LEAVE
0040D9C5 C2 1800 RETN 18
0040D9C8 33DB XOR EBX,EBX
0040D9CA 8B35 4C364100 MOV ESI,DWORD PTR DS:[41364C] ; 注册名长度入esi
0040D9D0 8D95 D0FBFFFF LEA EDX,DWORD PTR SS:[EBP-430] ; 注册名入edx,我自己取的注册名是loveboom
0040D9D6 B8 01000000 MOV EAX,1 ; 初始赋值eax为1
0040D9DB 0FB64C10 FF MOVZX ECX,BYTE PTR DS:[EAX+EDX-1] ; 依次读取注册名的每一位,用于后面的运算
0040D9E0 8BF8 MOV EDI,EAX ; a=1;for i=1 to 8
0040D9E2 83C7 03 ADD EDI,3 ; a=a+3 sasc=asc(mid(name,i,1))
0040D9E5 0FAFCF IMUL ECX,EDI ; b=sasc;b=b*a
0040D9E8 03D9 ADD EBX,ECX ; c=c+b
0040D9EA 40 INC EAX
0040D9EB 3BC6 CMP EAX,ESI
0040D9ED 77 02 JA SHORT KeygenMe.0040D9F1 ; 这里跳到下一步
0040D9EF ^ EB EA JMP SHORT KeygenMe.0040D9DB ; next
0040D9F1 8BC3 MOV EAX,EBX ; 运算后的结果195e入eax
0040D9F3 99 CDQ
0040D9F4 69C0 C9430000 IMUL EAX,EAX,43C9 ; 运算结果195e*43c9=6b784ce
0040D9FA 05 BBEF9505 ADD EAX,595EFBB ; eax=6b784ce+595efbb
0040D9FF 8BF0 MOV ESI,EAX ; 计算后的结果放入esi中(0c4d7489)
0040DA01 56 PUSH ESI
0040DA02 68 00304100 PUSH KeygenMe.00413000 ; ASCII "%1d"
0040DA07 8D45 D0 LEA EAX,DWORD PTR SS:[EBP-30]
0040DA0A 50 PUSH EAX
0040DA0B E8 580D0000 CALL KeygenMe.0040E768 ; JMP to USER32.wsprintfA
0040DA10 83C4 0C ADD ESP,0C
0040DA13 8B0D 50364100 MOV ECX,DWORD PTR DS:[413650]
0040DA19 8D75 D0 LEA ESI,DWORD PTR SS:[EBP-30]
0040DA1C 8DBD D0FAFFFF LEA EDI,DWORD PTR SS:[EBP-530]
0040DA22 FC CLD
0040DA23 A6 CMPS BYTE PTR DS:[ESI],BYTE PTR ES:[EDI]
0040DA24 75 25 JNZ SHORT KeygenMe.0040DA4B ; 这里注册码和第一次的运算结果比较如果相算就完了
0040DA26 49 DEC ECX
0040DA27 ^ 75 FA JNZ SHORT KeygenMe.0040DA23
0040DA29 C785 CCFAFFFF 01>MOV DWORD PTR SS:[EBP-534],1
0040DA33 6A 10 PUSH 10 ; 如果到了这里就不好玩了,下面就提示出错了
0040DA35 FF75 0C PUSH DWORD PTR SS:[EBP+C]
0040DA38 FF75 1C PUSH DWORD PTR SS:[EBP+1C]
0040DA3B FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040DA3E FF15 B0374100 CALL DWORD PTR DS:[4137B0] ; KeygenMe.0040E79E
0040DA44 5B POP EBX
0040DA45 891D 5C364100 MOV DWORD PTR DS:[41365C],EBX
0040DA4B C785 CCFAFFFF 00>MOV DWORD PTR SS:[EBP-534],0 ; 不相等就跳到这里
0040DA55 5F POP EDI
0040DA56 5E POP ESI
0040DA57 5B POP EBX
0040DA58 C9 LEAVE
0040DA59 C2 1800 RETN 18
返回到这里:
0040DFD1 E8 F0050000 CALL KeygenMe.0040E5C6 ;这里大概看一下,因为好晚了,也因为我想睡所以没有跟下去找算法
0040DFD6 8D85 9CE3FFFF LEA EAX,DWORD PTR SS:[EBP-1C64]
0040DFDC 50 PUSH EAX
0040DFDD 8D85 9CE7FFFF LEA EAX,DWORD PTR SS:[EBP-1864]
上面的call进来看到一个异常,我就没跟了:
0040E5C6 C705 94314100 F5>MOV DWORD PTR DS:[413194],KeygenMe.0040E5F5
0040E5D0 892D 90314100 MOV DWORD PTR DS:[413190],EBP
0040E5D6 68 31104000 PUSH KeygenMe.00401031 ; 异常回到的地方
0040E5DB 64:FF35 00000000 PUSH DWORD PTR FS:[0] ; 这里准备异常了
0040E5E2 8925 8C314100 MOV DWORD PTR DS:[41318C],ESP
0040E5E8 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
0040E5EF 33F6 XOR ESI,ESI
0040E5F1 33C0 XOR EAX,EAX ; 这里开始异常了
0040E5F3 8900 MOV DWORD PTR DS:[EAX],EAX
0040E5F5 64:8F05 00000000 POP DWORD PTR FS:[0]
懒了,没跟下去,直接在下面找到那个跳转.
0040E054 E8 5EFBFFFF CALL KeygenMe.0040DBB7
0040E059 23C0 AND EAX,EAX ;这里置eax为1就暴破了
0040E05B 74 1F JE SHORT KeygenMe.0040E07C
0040E05D 8D85 9CEFFFFF LEA EAX,DWORD PTR SS:[EBP-1064]
0040E063 50 PUSH EAX
0040E064 8D85 3AFAFFFF LEA EAX,DWORD PTR SS:[EBP-5C6]
0040E06A 50 PUSH EAX
0040E06B 8D85 D6FAFFFF LEA EAX,DWORD PTR SS:[EBP-52A]
0040E071 50 PUSH EAX
0040E072 FF75 08 PUSH DWORD PTR SS:[EBP+8]
0040E075 E8 C9F7FFFF CALL KeygenMe.0040D843 ;这里进去就是MessageBoxA
0040E07A EB 1D JMP SHORT KeygenMe.0040E099
到此暴破完毕,在上面要注意一下的就是程序有了不少异常来干扰我们的视线,特别注意的是,遇到int3的时候一定要记得按shift+f9.下面进入第二个环节,脱掉它全部的马甲,让它“全?”.
如果只是脱的话,一下就脱掉了,我想讲讲大概的方法,最后快速脱壳
再次载入目标.设置不变:入口处看到不少90,但有一句明显的jmp eax,所以直接到jmp eax处
00438029 90 NOP
0043802A 90 NOP
0043802B B8 01604300 MOV EAX,KeygenMe.00436001
00438030 FFE0 JMP EAX ;载入后f4到这里
现在看到第一层壳了:
00436001 60 PUSHAD
00436002 E8 03000000 CALL KeygenMe.0043600A
00436007 - E9 EB045D45 JMP 45A064F7
peid说是PENinja -> +DZA Kracker/TNT!的壳,不过我看到之后倒觉得是aspack来的.
到第一层壳处按f7到这里
0043601C 81EB 00600300 SUB EBX,36000
00436022 83BD 22040000 00 CMP DWORD PTR SS:[EBP+422],0
00436029 899D 22040000 MOV DWORD PTR SS:[EBP+422],EBX ; KeygenMe.00400000
0043602F 0F85 65030000 JNZ KeygenMe.0043639A
现在直接在43639a处按f4运行到那里,到达后(这个过程可能慢一点)按几次f8到一个新地方了:
00435000 55 PUSH EBP
00435001 8BEC MOV EBP,ESP
00435003 6A FF PUSH -1
00435005 68 14135200 PUSH 521314
这里不是OEP来的,原因:你看看相关代码就明白了,再按一会f8到第二层壳了
这里第二层
00427000 60 PUSHAD
00427001 E8 00000000 CALL KeygenMe.00427006
00427006 5D POP EBP
这里就不要一步一步跟了,因为跟过一两次之后就知道,这个壳有点像svkp来的,所以到这里后,我们按f9运行,这样就会出现svkp典型异常
042E137F 6285 0E0B0000 BOUND EAX,QWORD PTR SS:[EBP+B0E] ;这里异常
042E1385 EB 02 JMP SHORT 042E1389
异常后,我们在code段按f2,下断后,shift+f9运行,这样就到这里:
0430B6B1 8A06 MOV AL,BYTE PTR DS:[ESI] ;断在这里
0430B6B3 46 INC ESI
0430B6B4 47 INC EDI
0430B6B5 8843 0F MOV BYTE PTR DS:[EBX+F],AL
0430B6B8 8A46 FF MOV AL,BYTE PTR DS:[ESI-1]
0430B6BB 55 PUSH EBP
0430B6BC E8 00000000 CALL 0430B6C1
0430B6C1 5D POP EBP
0430B6C2 81ED 0D470000 SUB EBP,470D
0430B6C8 8A8D 50030000 MOV CL,BYTE PTR SS:[EBP+350]
0430B6CE 5D POP EBP
0430B6CF 32C1 XOR AL,CL
0430B6D1 8847 FF MOV BYTE PTR DS:[EDI-1],AL
0430B6D4 8BC5 MOV EAX,EBP
0430B6D6 4D DEC EBP
0430B6D7 85C0 TEST EAX,EAX
0430B6D9 ^ 75 A4 JNZ SHORT 0430B67F
0430B6DB 33C0 XOR EAX,EAX
0430B6DD 5D POP EBP
0430B6DE 5F POP EDI
0430B6DF 5E POP ESI
0430B6E0 5B POP EBX
0430B6E1 C2 1400 RETN 14 ;直接F4到这里
现在再在code段F2下断并运行,这样很快就到了第三个壳的地方:
第三层(好像是早期的aspr来的):
00401000 68 01504100 PUSH KeygenMe.00415001 ;呵呵,直接停在这里
00401005 E8 01000000 CALL KeygenMe.0040100B
0040100A C3 RETN
看到早期的aspr的就好办了,取消内存异常,第十六次异常后停在这里:
0040E5F3 8900 MOV DWORD PTR DS:[EAX],EAX
0040E5F5 64:8F05 00000000 POP DWORD PTR FS:[0]
0040E5FC 83C4 04 ADD ESP,4
0040E5FF C705 94314100 33>MOV DWORD PTR DS:[413194],KeygenMe.0040E633
0040E609 892D 90314100 MOV DWORD PTR DS:[413190],EBP
0040E60F 68 31104000 PUSH KeygenMe.00401031
0040E614 64:FF35 00000000 PUSH DWORD PTR FS:[0]
0040E61B 8925 8C314100 MOV DWORD PTR DS:[41318C],ESP
0040E621 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
0040E628 33DB XOR EBX,EBX
0040E62A 33D2 XOR EDX,EDX
0040E62C B8 02000000 MOV EAX,2
0040E631 F7F3 DIV EBX
0040E633 64:8F05 00000000 POP DWORD PTR FS:[0]
0040E63A 83C4 04 ADD ESP,4
0040E63D C3 RETN ;直接在这里下f2,然后shift+f9就会运行到这里的.
停在retn处后,再按一次f8就到了程序的OEP:
0040E707 6A 00 PUSH 0 ;OEP
0040E709 68 EBDB4000 PUSH KeygenMe.0040DBEB
0040E70E 6A 00 PUSH 0
到此oep就找到了,用impr用level1找一下就剩2个无效的api,用aspr1.22的插件或手工都轻松搞定。
知道怎么回事之后,我现在要快速脱它,
载入目标,按f9运行程序,异常后再在code段下f2??>shift+f9然后,f4到retn 14处à在code段下f2àf9运行这样到了aspr层,后面的按aspr的方法就可以一下搞定,我自己是写一下脚本:
var cbase
var csize
var count
gmi eip,CODEBASE
mov cbase,$RESULT
gmi eip,CODESIZE
mov csize,$RESULT
mov count,10
start:
run
lbl1:
bprm cbase,csize
esto
lbl2:
bpmc
findop eip,#C21400#
go $RESULT
lbl3:
bprm cbase,csize
run
lbl4:
bpmc
cmt eip,"取消内存异常项,然后按resume继续!"
pause
lbl5:
eoe lbl6
run
lbl6:
cmp count,0
je lbl7
sub count,1
esto
jmp lbl6
lbl7:
findop eip,#C3#
bp $RESULT
eob lbl8
eoe lbl8
esto
lbl8:
bc $RESULT
sto
cmt eip,"Hehe!"
ret
到此就算基本解决问题了。
【总 结】:
好想睡了,各位看官自己看看有什么问题,明天再说吧.
Thanks:
Fly 辉仔yock、jingulong、tDasm、David、ahao、ufo(brother)、alan(sister)、所有曾经关心支持或帮助过我的朋友!谢谢您们!
by loveboom[DFCG][FCG]
Email:bmd2chen@tom.com
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!