从看雪下的CM太多了,随便拿个来学习下,第一次写破文,不好不要见笑啊!也不知有没有写过这个的,如有重复实属意外。高手飘过!
附件:
gge.rar
首先用PE检查有无加壳及其是什么软件编写的。恩,没有加壳且是VC编写的,运气不错!
VC个人觉得还是比较好看懂的!
运行之查看基本情况,简单的界面,可是发现确定按扭无法使用,看来是被作者禁止使用了,没有确定如何注册?看来先要把它变成可以使用才行。
查资料得知,EnbleWindow、EnbleMenuItem使用来把按扭变成灰色的
OK,把文件丢近OD,用API工具在两函数下断点
运行之,OD断下,停在USER32系统领空
汇编代码如下
77D29849 U> 8BFF mov edi,edi ; USER32.SendMessageA
77D2984B 55 push ebp
77D2984C 8BEC mov ebp,esp
77D2984E 6A 60 push 60
77D29850 FF75 0C push dword ptr ss:[ebp+C]
77D29853 FF75 08 push dword ptr ss:[ebp+8]
77D29856 E8 DAFFFFFF call USER32.77D29835
这里应该是发送一个消息使之变灰的函数
查看下堆栈窗口
0012F7EC 73D37E00 /CALL 到 EnableWindow 来自 MFC42.73D37DFA
0012F7F0 0007057E |hWnd = 0007057E ('确 定',class='Button',parent=000E0532)
0012F7F4 00000000 \Enable = FALSE
堆栈的参数都是由调用的函数传递过来的
可以看出Enable = FALSE是确定按扭不能使用的罪魁祸首
ALT+F9返回程序,查看函数调用前参数情况
代码如下
00401513 . 6A 00 push 0
00401515 . 68 EA030000 push 3EA
0040151A . 8BCE mov ecx,esi
0040151C . E8 FB040000 call <jmp.&MFC42.#3092>
00401521 . 8BC8 mov ecx,eax
00401523 . E8 EE040000 call <jmp.&MFC42.#2642>
00401528 . 8B4C24 0C mov ecx,dword ptr ss:[esp+C]
0040152C . 5F pop edi
0040152D . B8 01000000 mov eax,1
00401532 . 5E pop esi
00401533 . 64:890D 000000>mov dword ptr fs:[0],ecx
0040153A . 83C4 10 add esp,10
返回到00401528,往前既是传递的参数
PUSH 0,有问题!改之,PUSH 1
保存之
运行,按扭可以使用
解决按扭问题
为什么改PUSH 1就可以了呢?
疑问,查阅API函数大全如下
Declare Function EnableWindow Lib "user32" Alias "EnableWindow" (ByVal hwnd As Long, ByVal fEnable As Long) As Long
说明 在指定的窗口里允许或禁止所有鼠标及键盘输入(在vb里使用:在vb窗体和控件中使用Enabled属性) 返回值 Long,非零表示成功,零表示失败。会设置GetLastError 参数表 参数 类型及说明 hwnd Long,窗口句柄 fEnable Long,非零允许窗口,零禁止
VC传递参数由右边往左传,所以
00401513 . 6A 00 push 0
00401515 . 68 EA030000 push 3EA
fEnable = 0;hwnd=3EA
把0改为一就可以完成第一步了
===============================================================
在运行文件为第二步准备
随便输入 用户名:123 密码abc
出错,有提示(好现象)
用OD插件查找字符串
OH!GOOD!字符串找到如下
Ultra 字符串参考
地址 反汇编 文本字符串
00401528 mov ecx,dword ptr ss:[esp+C] (初始化 CPU 选择状态)
004016B2 mov esi,gge.0040304C hanyu
004016EF mov esi,gge.00403044 9527888hanyu
00401729 push gge.00403034 恭喜你成功了!
0040173D push gge.00403020 别灰心,继续努力!
00401762 mov esi,gge.00403054 William
OK。双击00401729到如下代码
004016A0 . 53 push ebx
004016A1 . 56 push esi
004016A2 . 57 push edi
004016A3 . 8BF9 mov edi,ecx
004016A5 . 6A 01 push 1
004016A7 . E8 A0030000 call <jmp.&MFC42.#6334>
004016AC . 8B87 E4000000 mov eax,dword ptr ds:[edi+E4] ;用户名放进EAX
004016B2 . BE 4C304000 mov esi,gge.0040304C ; ASCII "hanyu"取内存地址40304C处的值并传递给ESI
004016B7 > 8A10 mov dl,byte ptr ds:[eax] ;按字节把输入的用户名传递给DL寄存器
004016B9 . 8A1E mov bl,byte ptr ds:[esi] ;把ESI中的字符按位传递给BL
004016BB . 8ACA mov cl,dl ;DL中的数值传递给CL
004016BD . 3AD3 cmp dl,bl ;比较两寄存器值
004016BF . 75 1E jnz short gge.004016DF ;不等则跳
004016C1 . 84C9 test cl,cl ;是否取完
004016C3 . 74 16 je short gge.004016DB ;完了就跳
004016C5 . 8A50 01 mov dl,byte ptr ds:[eax+1] ;传递下一位输入用户名
004016C8 . 8A5E 01 mov bl,byte ptr ds:[esi+1] ;传递下一位固定值
004016CB . 8ACA mov cl,dl ;
004016CD . 3AD3 cmp dl,bl
004016CF . 75 0E jnz short gge.004016DF ;不等跳
004016D1 . 83C0 02 add eax,2 ;EAX+2(下一位)
004016D4 . 83C6 02 add esi,2 ;ESI+2
004016D7 . 84C9 test cl,cl ;是否完
004016D9 .^ 75 DC jnz short gge.004016B7 ;完跳
004016DB > 33C0 xor eax,eax
004016DD . EB 05 jmp short gge.004016E4
004016DF > 1BC0 sbb eax,eax ;注意这个运算符,不是SUB哦
004016E1 . 83D8 FF sbb eax,-1
004016E4 > 83F8 01 cmp eax,1
004016E7 . 75 50 jnz short gge.00401739
004016E9 . 8B87 E8000000 mov eax,dword ptr ds:[edi+E8]
004016EF . BE 44304000 mov esi,gge.00403044 ; ASCII "9527888"
004016F4 > 8A10 mov dl,byte ptr ds:[eax]
004016F6 . 8A1E mov bl,byte ptr ds:[esi]
004016F8 . 8ACA mov cl,dl
004016FA . 3AD3 cmp dl,bl
004016FC . 75 1E jnz short gge.0040171C
004016FE . 84C9 test cl,cl
00401700 . 74 16 je short gge.00401718
00401702 . 8A50 01 mov dl,byte ptr ds:[eax+1]
00401705 . 8A5E 01 mov bl,byte ptr ds:[esi+1]
00401708 . 8ACA mov cl,dl
0040170A . 3AD3 cmp dl,bl
0040170C . 75 0E jnz short gge.0040171C
0040170E . 83C0 02 add eax,2
00401711 . 83C6 02 add esi,2
00401714 . 84C9 test cl,cl
00401716 .^ 75 DC jnz short gge.004016F4
00401718 > 33C0 xor eax,eax
0040171A . EB 05 jmp short gge.00401721
0040171C > 1BC0 sbb eax,eax
0040171E . 83D8 FF sbb eax,-1
00401721 > 85C0 test eax,eax
00401723 . 6A 00 push 0
00401725 . 6A 00 push 0
00401727 . 75 14 jnz short gge.0040173D
00401729 . 68 34304000 push gge.00403034 ;跳这就对
0040172E . 8BCF mov ecx,edi
00401730 . E8 11030000 call <jmp.&MFC42.#4224>
00401735 . 5F pop edi
00401736 . 5E pop esi
00401737 . 5B pop ebx
00401738 . C3 retn
00401739 > 6A 00 push 0 ;任何跳转到这就会有出错框了,所以有有跳到这不行
0040173B . 6A 00 push 0
0040173D > 68 20304000 push gge.00403020
00401742 . E8 F9020000 call <jmp.&MFC42.#1200>
00401747 . 5F pop edi
00401748 . 5E pop esi
00401749 . 5B pop ebx
0040174A . C3 retn
出现两个可疑字符hanyu,9527888
酷似用户名和密码哦(窃喜,太简单了吧)
抱着一试的态度输入
OH!NO!出错的提示筐击碎了我弱小的心
看来只有跟跟看了
往上翻之,004016A0之前代码全是NOP,经验在此断之
F9运行,单步F8,到004016AC时,EAX得到输入用户名字符,可以想象可能要处理用户名了,往下翻翻代码
得到结论如下
。输入的用户名处理符合要求则处理输入的注册码,码对则正确
2。注册码处理较为简单,只是和固定值做按位比较
2。用户名的处理规则为:前一为符合要求则后面不用处理;只是和hanyu按位比较,如相同则错;第一不等,后面随便输;第一位等,二位不等,后随便输…
随意实验
o,9527888;ho,9527888;hat,9527888;都正确
。正得意间,用a,9527888试之,错误框在次出现!心情马上跌入谷地!
还有点问题
没办法,回头再次重新阅读代码
终于找到问题所在,一个奇怪的代码被发现
0040171C > 1BC0 sbb eax,eax
显然我是直接把它当成减法运算了
仔细一看才知道并不简单的减法
查阅资料
带借位减去指令 SBB(SuBtraction with Borrow)
格式: SBB OPRD1,OPRD2
功能: 是进行两个操作数的相减再减去CF进位标志位,即从OPRD1<--OPRD1-OPRD2-CF,其结果放在OPDR1中.
原来最后还要与CF寄存器运算
CF运算器是啥呢?继续查
CF为进位标志位,当两个数据相加的时候,有可能产生从最高有效位向更高的进位。此进位标志放于CF中
加法运算可以影响其数值
上翻代码,没有发现加减法运算耶,迷茫
发现一CMP比较运算符
查阅资料,原来CMP也要影响CF标志位
恩,最终明白,每一位的ASC值都不能比固定值小
最后在发现没有限制用户名的长度,而固定值字符后ASC值都为0,所以前五位可以为hanyu,后在随便输任意字符都可以对,不知道作者是不是故意的!
总结
学习了VC下用EnbleWindow把灰色按扭变成可用按扭
学习了SBB运算符及CF标志位
=========================================================
第一次写,不要见笑啊
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)