初识破解与程序(C语言控制台程序)之间的关系
本帖最后由 玖公子 于 2019-8-16 09:50 编辑我是刚来论坛的,第一次发帖!
对版规不是很熟悉,如果发错区了,请管理大大手下留情,不要扣分,谢谢!
初识破解与程序之间的关系:
1、用VC++6.0编写一个简单的C语言程序
这个程序我们输入正确的key,就能输出成功的提示信息!
程序和源代码见附件!
2、我们将程序载入OD,停在了
0040130D >/$55 push ebp
0040130E|.8BEC mov ebp,esp
00401310|.6A FF push -0x1
00401312|.68 B8604000 push test01.004060B8
00401317|.68 EC2C4000 push test01.00402CEC ;SE 处理程序安装
0040131C|.64:A1 0000000>mov eax,dword ptr fs:
00401322|.50 push eax
00401323|.64:8925 00000>mov dword ptr fs:,esp
0040132A|.83EC 10 sub esp,0x10
0040132D|.53 push ebx
0040132E|.56 push esi
0040132F|.57 push edi
00401330|.8965 E8 mov ,esp
00401333|.FF15 04604000 call dword ptr ds:[<&KERNEL32.GetVersion>;kernel32.GetVersion
00401339|.33D2 xor edx,edx ;ntdll.KiFastSystemCallRet
0040133B|.8AD4 mov dl,ah
0040133D|.8915 44994000 mov dword ptr ds:,edx ;ntdll.KiFastSystemCallRet
我们F8向下走,看到call test01.00401000
00401378|> \8365 FC 00 and ,0x0
0040137C|.E8 B4000000 call test01.00401435
00401381|.FF15 00604000 call dword ptr ds:[<&KERNEL32.GetCommand>; [GetCommandLineA
00401387|.A3 449E4000 mov dword ptr ds:,eax
0040138C|.E8 5C150000 call test01.004028ED
00401391|.A3 20994000 mov dword ptr ds:,eax
00401396|.E8 05130000 call test01.004026A0
0040139B|.E8 47120000 call test01.004025E7
004013A0|.E8 7E050000 call test01.00401923
004013A5|.A1 54994000 mov eax,dword ptr ds:
004013AA|.A3 58994000 mov dword ptr ds:,eax
004013AF|.50 push eax
004013B0|.FF35 4C994000 push dword ptr ds:
004013B6|.FF35 48994000 push dword ptr ds:
004013BC|.E8 3FFCFFFF call test01.00401000
00401000我们知道这是code(代码)段,004013BC这一行F7进去,来到了
00401000/$E8 BB000000 /call test01.004010C0
00401005|.85C0 |test eax,eax
00401007|.75 0F |jnz short test01.00401018
00401009|.68 44704000 |push test01.00407044 ;很遗憾,失败了! \n
0040100E|.E8 7F020000 |call test01.00401292
00401013|.83C4 04 |add esp,0x4
00401016|.^ EB E8 \jmp short test01.00401000
00401018|>68 30704000 push test01.00407030 ;恭喜你,成功了! \n
很明显,这里有一个判断语句,只要将jnz改成jmp,将程序保存出去,就破解成功了!
3.我们在00401000这个call继续F7进去,看到了
004010C0/$83EC 14 sub esp,0x14
004010C3|.57 push edi
004010C4|.68 68704000 push test01.00407068 ;请输入一个key:\n
004010C9|.E8 C4010000 call test01.00401292
004010CE|.8D4424 08 lea eax,dword ptr ss:
004010D2|.50 push eax
004010D3|.E8 EB010000 call test01.004012C3
004010D8|.8D7C24 0C lea edi,dword ptr ss:
004010DC|.83C9 FF or ecx,-0x1
004010DF|.33C0 xor eax,eax
004010E1|.F2:AE repne scas byte ptr es:
004010E3|.F7D1 not ecx ;test01.004070F0
004010E5|.49 dec ecx ;test01.004070F0
004010E6|.51 push ecx ;test01.004070F0
004010E7|.8D4C24 10 lea ecx,dword ptr ss:
004010EB|.51 push ecx ;test01.004070F0
004010EC|.E8 5FFFFFFF call test01.00401050
004010F1|.83C4 10 add esp,0x10
004010F4|.5F pop edi ;test01.00401005
004010F5|.83C4 14 add esp,0x14
004010F8\.C3 retn
这里有三个call,后面retn就回到了00401005比较的地方了!第一个call应该是获取用户输入的函数,
我们从004010D3第二个callF7进去看看!
004012C3/$56 push esi
004012C4|.57 push edi
004012C5|.8B7C24 0C mov edi,dword ptr ss:
004012C9|.8BF7 mov esi,edi
004012CB|>FF0D 84704000 /dec dword ptr ds:
004012D1|.78 10 |js short test01.004012E3
004012D3|.A1 80704000 |mov eax,dword ptr ds: ;99\n\n\n
004012D8|.0FB600 |movzx eax,byte ptr ds:
004012DB|.FF05 80704000 |inc dword ptr ds: ;test01.00409E60
004012E1|.EB 0B |jmp short test01.004012EE
004012E3|>68 80704000 |push test01.00407080 ;99\n\n\n
004012E8|.E8 13FEFFFF |call test01.00401100
004012ED|.59 |pop ecx ;test01.004010D8
004012EE|>83F8 0A |cmp eax,0xA
004012F1|.74 12 |je short test01.00401305
004012F3|.83F8 FF |cmp eax,-0x1
004012F6|.74 05 |je short test01.004012FD
004012F8|.8806 |mov byte ptr ds:,al
004012FA|.46 |inc esi
004012FB|.^ EB CE \jmp short test01.004012CB
004012FD|>3BF7 cmp esi,edi
004012FF|.75 04 jnz short test01.00401305
00401301|.33FF xor edi,edi
00401303|.EB 03 jmp short test01.00401308
00401305|>8026 00 and byte ptr ds:,0x0
00401308|>8BC7 mov eax,edi
0040130A|.5F pop edi ;test01.004010D8
0040130B|.5E pop esi ;test01.004010D8
0040130C\.C3 retn
从004012CB这里到004012FB这里就是循环加密字符串的地方,004012E8这个call我们F7进去,
F8向下继续走,看到00401148|.E8 93040000 call test01.004015E0这一行再次F7进去。
继续F8,发现00401664这个callF8后,程序跑起来了
00401664|.FF15 20604000 call dword ptr ds:[<&KERNEL32.ReadFile>] ; \ReadFile
我们切换到程序,输入几个字符,继续向下F8,观察这段代码!
004016E7|> /8B45 10 /mov eax, ;test01.00409E60
004016EA|. |8A00 |mov al,byte ptr ds:
004016EC|. |3C 1A |cmp al,0x1A
004016EE|. |0F84 AE000000 |je test01.004017A2
004016F4|. |3C 0D |cmp al,0xD
004016F6|. |74 0B |je short test01.00401703
004016F8|. |8807 |mov byte ptr ds:,al
004016FA|. |47 |inc edi ;test01.00409E60
004016FB|. |FF45 10 |inc ;test01.00409E60
004016FE|. |E9 91000000 |jmp test01.00401794
00401703|> |49 |dec ecx ;test01.00409E70
00401704|. |394D 10 |cmp ,ecx ;test01.00409E70
00401707|. |73 18 |jnb short test01.00401721
00401709|. |8B45 10 |mov eax, ;test01.00409E60
0040170C|. |40 |inc eax ;test01.00409E60
0040170D|. |8038 0A |cmp byte ptr ds:,0xA
00401710|. |75 06 |jnz short test01.00401718
00401712|. |8345 10 02 |add ,0x2
00401716|. |EB 5E |jmp short test01.00401776
00401718|> |C607 0D |mov byte ptr ds:,0xD
0040171B|. |47 |inc edi ;test01.00409E60
0040171C|. |8945 10 |mov ,eax ;test01.00409E60
0040171F|. |EB 73 |jmp short test01.00401794
00401721|> |8D45 F4 |lea eax,
00401724|. |6A 00 |push 0x0 ; /pOverlapped = NULL
00401726|. |50 |push eax ; |pBytesRead = test01.00409E60
00401727|. |FF45 10 |inc ; |test01.00409E60
0040172A|. |8D45 FF |lea eax,dword ptr ss: ; |
0040172D|. |6A 01 |push 0x1 ; |BytesToRead = 0x1
0040172F|. |50 |push eax ; |Buffer = test01.00409E60
00401730|. |8B03 |mov eax,dword ptr ds: ; |
00401732|. |FF3430 |push dword ptr ds: ; |hFile = 6F6C2049
00401735|. |FF15 20604000 |call dword ptr ds:[<&KERNEL32.ReadFile>>; \ReadFile
0040173B|. |85C0 |test eax,eax ;test01.00409E60
0040173D|. |75 0A |jnz short test01.00401749
0040173F|. |FF15 1C604000 |call dword ptr ds:[<&KERNEL32.GetLastEr>; [GetLastError
00401745|. |85C0 |test eax,eax ;test01.00409E60
00401747|. |75 47 |jnz short test01.00401790
00401749|> |837D F4 00 |cmp ,0x0
0040174D|. |74 41 |je short test01.00401790
0040174F|. |8B03 |mov eax,dword ptr ds:
00401751|. |F64430 04 48|test byte ptr ds:,0x48
00401756|. |74 13 |je short test01.0040176B
00401758|. |8A45 FF |mov al,byte ptr ss:
0040175B|. |3C 0A |cmp al,0xA
0040175D|. |74 17 |je short test01.00401776
0040175F|. |C607 0D |mov byte ptr ds:,0xD
00401762|. |8B0B |mov ecx,dword ptr ds:
00401764|. |47 |inc edi ;test01.00409E60
00401765|. |884431 05 |mov byte ptr ds:,al
00401769|. |EB 29 |jmp short test01.00401794
0040176B|> |3B7D 0C |cmp edi, ;test01.00409E60
0040176E|. |75 0B |jnz short test01.0040177B
00401770|. |807D FF 0A |cmp byte ptr ss:,0xA
00401774|. |75 05 |jnz short test01.0040177B
00401776|> |C607 0A |mov byte ptr ds:,0xA
00401779|. |EB 18 |jmp short test01.00401793
0040177B|> |6A 01 |push 0x1
0040177D|. |6A FF |push -0x1
0040177F|. |FF75 08 |push
00401782|. |E8 E4180000 |call test01.0040306B
00401787|. |83C4 0C |add esp,0xC
0040178A|. |807D FF 0A |cmp byte ptr ss:,0xA
0040178E|. |74 04 |je short test01.00401794
00401790|> |C607 0D |mov byte ptr ds:,0xD
00401793|> |47 |inc edi ;test01.00409E60
00401794|> |8B4D F8 |mov ecx, ;test01.00409E70
00401797|. |394D 10 |cmp ,ecx ;test01.00409E70
0040179A|.^\0F82 47FFFFFF \jb test01.004016E7
核心加密代码如下(这段代码循环对字符串进行处理):
004016E7|> /8B45 10 /mov eax, ;test01.00409E65
004016EA|. |8A00 |mov al,byte ptr ds:
004016EC|. |3C 1A |cmp al,0x1A
004016EE|. |0F84 AE000000 |je test01.004017A2
004016F4|. |3C 0D |cmp al,0xD
004016F6|. |74 0B |je short test01.00401703
004016F8|. |8807 |mov byte ptr ds:,al
004016FA|. |47 |inc edi ;test01.00409E65
004016FB|. |FF45 10 |inc ;test01.00409E65
将我们输入的字符串赋值给eax,每次加1。这里需要百度一下inc指令的作用!
加一指令inc
inc a 相当于 add a,1 //i++
优点 速度比sub指令快,占用空间小
这条指令执行结果影响AF、OF、PF、SF、ZF标志位,但不影响CF进位标志位。
4.找到了加密算法,我们接着去找加密后的字符串,肯定是有个比较,才能判断是否跳转成功or失败!
第3步刚开始的时候有三个call,第二个call是加密字符串,第三个call肯定是进行了比较,因为retn后
就直接跳转到成功or失败了!
我们Ctrl+G输入第三个call的地址004010EC,F4运行过来(切到程序程序窗口,输入一串字母,停在了这里),
然后F7进去,看到
00401060|> /8A1C08 /mov bl,byte ptr ds:
00401063|. |FEC3 |inc bl
00401065|. |881C08 |mov byte ptr ds:,bl
00401068|. |40 |inc eax
00401069|. |3BC2 |cmp eax,edx
0040106B|.^\7C F3 \jl short test01.00401060
在这里我们输入的字符串一个一个就循环加密完成了!
0040106D|> \BE 58704000 mov esi,test01.00407058 ;J!mpwf!63qpkjf
这个J!mpwf!63qpkjf就是要比较的字符串!
00401074|> /8A10 /mov dl,byte ptr ds:
00401076|. |8A1E |mov bl,byte ptr ds:
00401078|. |8ACA |mov cl,dl
0040107A|. |3AD3 |cmp dl,bl
0040107C|. |75 28 |jnz short test01.004010A6
0040107E|. |84C9 |test cl,cl
00401080|. |74 16 |je short test01.00401098
00401082|. |8A50 01 |mov dl,byte ptr ds:
00401085|. |8A5E 01 |mov bl,byte ptr ds:
00401088|. |8ACA |mov cl,dl
0040108A|. |3AD3 |cmp dl,bl
0040108C|. |75 18 |jnz short test01.004010A6
0040108E|. |83C0 02 |add eax,0x2
00401091|. |83C6 02 |add esi,0x2
00401094|. |84C9 |test cl,cl
00401096|.^\75 DC \jnz short test01.00401074
这一段代码就是在将我们输入的字符串加密后与J!mpwf!63qpkjf这个字符串逐个比较!
如果相等,执行下面的汇编代码
00401098|> \33C0 xor eax,eax
0040109A|.33C9 xor ecx,ecx
0040109C|.85C0 test eax,eax
0040109E|.0f94c1 sete cl
004010A1|.5E pop esi ;test01.004013C1
004010A2|.8BC1 mov eax,ecx
004010A4|.5B pop ebx ;test01.004013C1
004010A5|.C3 retn
如果不相等,执行下面的汇编代码
004010A6|> \1BC0 sbb eax,eax
004010A8|.5E pop esi ;test01.004013C1
004010A9|.83D8 FF sbb eax,-0x1
004010AC|.33C9 xor ecx,ecx
004010AE|.85C0 test eax,eax
004010B0|.0f94c1 sete cl
004010B3|.8BC1 mov eax,ecx
004010B5|.5B pop ebx ;test01.004013C1
004010B6\.C3 retn
然后就返回到00401000这一行,执行test eax,eax语句,决定输出成功or失败!
至此,程序分析完毕,如有认识不到位的地方,请大牛们指正!
源程序和代码下载的地址:https://www.lanzouj.com/i5l2laj 这个好的教程怎么没人回复 赞个 谢谢楼主分享 厉害厉害,谢谢楼主分享 感谢大神分享,点赞!!! 支持一下 感谢!! 厉害厉害,谢谢楼主分享 支持一下 看到这个才发现自己差了很多呀,真的很厉害,{:1_893:}
页:
[1]
2