好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 isgoodtime 于 2017-9-15 14:45 编辑
为了好好学习天天向上呢...我就拿着OD,参照自己写的源码,对照着分析了好久,感觉收获还是嘛大的.这就分享给大家.
1.首选我利用超级字符串插件,来到了Fuck按钮的点击事件里面.关键代码如下:
其实这里只是一个小诱骗,让人感觉好像只需要把jp给nop掉后就可以成功破解了.其实关键验证是在我下了断点的那个Call里面(004010B1 |. E8 43010000 call CM_含笑?004011F9)
接下来咱们运行程序,输入Name: 5555585 Key: isgoodtime ,(这里有个小技巧,就是输入这些名字的时候,最好输入一个特殊一点的,方便在堆栈中看到).然后点Fuck按钮,断下后按F7进Call看了
先看下源代码:源代码刚开始其实做了一小段的干扰,做了一段看似是用来验证的操作.取了硬盘特征字,还可以系统当前时间,然后还取了硬盘特征字的数据摘要
接下来咱们参照源代码来看看OD里面的汇编代码:
其实到这里面的时候我就一脸茫然了...但后来突然想起,这里面不是有一些固定的值嘛,像那句: 取文本长度 (输入的注册码) > 25
是不是明显有一个常数 25 ,嘿转换到十六进制是: 19 接下来,咱们就找找看哪里有19的字样.
我往下面翻了半天,好像还真找到一个,如下图:
是吧,参照代码一看...突然发现自己也看得一点点懂汇编代码耶,在图片里面我加了注释,这次分析呢,我还发现一个现象,那就是上面这张图片里面用红框框起来的汇编代码
其实那些代码本来不长这个样子,是通过OD分析代码后加上去的. 就像那句把伪结果+1的那一行代码(00401352 |. FF45 F4 inc [local.3] )
inc 后面是 local.3 , local 就是本地的意思嘛,我个人理解, local.3 就是本地变量3,然后我回过头去数那些变量,发现好像 那个是在第三个耶.如下图.
这里简单介绍一下那个 local.3 是怎么来的,因为这里的原始代码其实是这样的 00401352 FF45 F4 inc dword ptr ss:[ebp-0xC]
要怎么看呢,如下图,右键菜单中的 分析-->从模块中删除分析,咱们就可以看到原始代码了,想还是看到 local.3 的话,可以再点 右键菜单 分析-->分析代码(Ctrl+A).
这里既然咱们知道了那个 local.3 是对应源代码里面的 结果值 这个变量,那么咱们再往下看有没有 local.3 因为按照源代码,后还对这个变量进行了+1 -1的扣作.
这里我接着往下翻,果然没翻几页就找到了带 local.3 的汇编代码了.如下图,我拿汇编代码与易语言源代码进行了一一对照.
嘿,看到这里,突然感觉看汇编代码也变得简单起来了.
那么接下来,咱们分析分析 看看汇编代码是如何实现易语言里面的 "取硬盘特征字()" 这个方法,又是如何实现 "取现行时间()"这个方法的.
首先咱们先回到函数的头部 也就是这一行 004011F9 /$ 55 push ebp
靠...刚来我就有新发现...这个新发现是建立在刚刚的那番分析的基础上发现的.快看快看,如下图.
原来函数头部就已经对易语言里面的局部变量全部初始化了值.
既然变量全都找到了,那再配合之前的常数定位这两个方法,很快就能参照代码把这个函数的大部份Call的功能以及程序的一些逻辑给分析出来了.
我OD已写上了备注,因为截图的话太长,所以采用代码的方式,只把Call部分及少量逻辑代码按顺序贴上来.
看官请看下面代码
00401236 |. E8 75080000 call CM_含笑?00401AB0 ; 取硬盘特征字 () //这里为什么知道是这个函数后面会有分析步骤,请看官慢慢往后面看.
00401250 |. E8 5B080000 call CM_含笑?00401AB0 ; 猜测此Call是 到字节集()
00401265 |. E8 46080000 call CM_含笑?00401AB0 ; 取现行时间 () //这里为什么知道是这个函数后面会有分析步骤,请看官慢慢往后面看.
0040127E |. E8 2D080000 call CM_含笑?00401AB0 ; 猜测此Call是 到字节集()
00401294 |. E8 6CFEFFFF call CM_含笑?00401105 ; 猜测这些Call是连接两个字节集
004012A7 |. E8 FE070000 call CM_含笑?00401AAA ; 猜测这些Call是连接两个字节集
004012B7 |. E8 EE070000 call CM_含笑?00401AAA ; 猜测这些Call是连接两个字节集
004012CB |. E8 DA070000 call CM_含笑?00401AAA ; 猜测这些Call是连接两个字节集
004012D4 |. 8945 FC mov [local.1],eax ;最终将拼接好的字节集赋值给 [local.1](上面初始化变量得出[local.1]是易语言的局部变量 硬盘特征码,)
004012FA |. E8 C9070000 call CM_含笑?00401AC8 ; 此处Call作用不明
00401311 |. E8 94070000 call CM_含笑?00401AAA ; 取数据摘要 (硬盘特征码)
0040131A |. 8945 F8 mov [local.2],eax;把获取出来的数据摘要赋值给 [local.2](上面初始化变量得出[local.2]是易语言的局部变量 特征码MD5值)
00401324 |. 8B5D 0C mov ebx,[arg.2]
00401327 |. 8B03 mov eax,dword ptr ds:[ebx]
00401329 |. 85C0 test eax,eax
;这三行是检测[arg.2](输入的注册码)是否为空,(arg.2 argument.2的简写,argument就是参数的意思.还是老样子与代码对应得上)
;从这三行来看易语言编译后的代码有点啰嗦,明明两行可以搞定为什么要三行呢?有没有高人指点一下.
;是真的啰嗦呢还是有别的什么好处.
0040132B |. /75 05 jnz short CM_含笑?00401332 ;这行代码是接着上面那个检测非空来的,这里很有意思...如果[arg.2]为空的话,会赋予一串奇怪的字符
0040133D |. E8 6E070000 call CM_含笑?00401AB0 ; 取文本长度 (输入的注册码)
00401348 |. 837D E0 19 cmp [local.8],0x19 ; 找到了就是这里如果大于0x19
00401352 |. FF45 F4 inc [local.3] ; 然后就把伪结果+1
00401374 |. 8B45 F8 mov eax,[local.2]
00401377 |. 85C0 test eax,eax; 每次用字符串的时候,都会检测是否为空,如果为空就是 赋予一串奇怪的字符
00401355 |. 68 01030080 push 0x80000301
0040135A |. 6A 00 push 0x0
0040135C |. 68 01000000 push 0x1
00401361 |. 68 01030080 push 0x80000301
00401366 |. 6A 00 push 0x0
00401368 |. 68 02000000 push 0x2
0040136D |. 68 04000080 push 0x80000004
00401372 |. 6A 00 push 0x0
00401374 |. 8B45 F8 mov eax,[local.2]
00401377 |. 85C0 test eax,eax ; 每次都会检测是否为空
00401379 |. 75 05 jnz short CM_含笑?00401380
0040137B |. B8 F8DC4600 mov eax,CM_含笑?0046DCF8
00401380 |> 50 push eax
00401381 |. 68 03000000 push 0x3
00401386 |. BB B01C4000 mov ebx,CM_含笑?00401CB0
0040138B |. E8 20070000 call CM_含笑?00401AB0 ; 取文本中间 (特征码MD5值, 2, 1)
;这里要说明一下,仔细看,上面的
0040135C 处的 push 0x1 和
00401368 处的 push 0x2 以及
00401374 mov eax,[local.2]
,刚好与易语言代码的 取文本中间 (特征码MD5值, 2, 1)的后面三个参数对应,我个人感觉...这种代码如果看得多了,以后一眼就能看出
是调用了易语言的支持库里面的哪个函数了.不过要达到这种程度,咱们还需下好几年功夫吧?
004013CE |. E8 DD060000 call CM_含笑?00401AB0 ; 取文本中间 (输入的注册码, 1, 1),这里也可以参照上面的分析,可以看看上面的参数.
004013E0 |. E8 77FDFFFF call CM_含笑?0040115C ; 作用不明...暂时跳过,以后分析
004013FE |. E8 A7060000 call CM_含笑?00401AAA ; 作用不明...暂时跳过,以后分析
0040140E |. E8 97060000 call CM_含笑?00401AAA ;为了对比两个文本型是否相等,似乎这里写了很多汇编代码,上面都有两个Call
00401420 |. FF45 F4 inc [local.3] ; 结果值 = 结果值 + 1
00401428 |> \FF4D F4 dec [local.3] ; 结果值 = 结果值 - 1
00401430 |> \FF4D F4 dec [local.3] ; 结果值 = 结果值 - 1
00401433 |> \FF75 0C push [arg.2] ; 接下来三行,很明显
00401436 |. FF75 08 push [arg.1] ; 连续传了两个 [arg.2],[arg.1]
00401439 |. E8 42010000 call CM_含笑?00401580 ; 将名字和注册传至验证程序 (输入的名字, 输入的注册码)
好好好...下面的代码分析着分析着我突然...发现了一个问题,就是之前咱们学习的东西有点问题.
前面咱们说的 变量的位置与 [local.数字是对应的] 看下面这个截图...原来之前咱们意淫的观点不正确...
看来每次学习新知识,除了要会意淫(猜测),还得动手验证一下观点正不正确.否则后果不堪设想.
从这张图片可以看出来...之前上面咱们所理解的,[local.几] 就是第几个参数.是错误的,这里明显反的对不对.还好这里有个常数0x1F0FF,要不是有这个常数...我也会迷迷糊糊的把这个问题给带过去了.因为有常数值的时候,看着看着,才发现用之前的那个按变量顺序编号的方法有点问题.
但这里我再先意淫一次,从这里来看,好像是变量在代码谁先出现,就是谁排在第一,虽然现在是意淫,等会我会再去写一个易语言测试程序,来验证一下这个意淫出来的观点.
好啦好啦 ,再接着把下面几个Call的功能都列出来,全列完之后,我就来说我是怎么知道这些Call是对应易语言里面的那一行代码的.
00401457 |. E8 54060000 call CM_含笑?00401AB0 ; 取窗口句柄()
0040146E |. E8 49060000 call CM_含笑?00401ABC ; 从下一行的 [local.4]可以看,这一行是 取窗口进程ID (取窗口句柄 (), 程序进程ID)
00401473 |. 837D F0 00 cmp [local.4],0x0 ; 如果真 (程序进程ID ≠ 0)
00401485 |. 68 FF0F1F00 push 0x1F0FFF ; 从这个立即数0x1F0FF=2035711可以看出,下面是调用打开进程
0040148F |. E8 28060000 call CM_含笑?00401ABC ; 打开进程 (2035711, 0, 程序进程ID)
00401497 |. 837D EC 00 cmp [local.5],0x0 ; 如果真 (窗口进程ID ≠ 0)
004014A1 |. 68 00000000 push 0x0
004014A6 |. 68 00000000 push 0x0
004014AB |. 68 00000000 push 0x0
004014B0 |. 68 F2194000 push CM_含笑?004019F2
004014B5 |. 68 00000000 push 0x0
004014BA |. 68 00000000 push 0x0
004014BF |. FF75 EC push [local.5]
004014C2 |. B8 02000000 mov eax,0x2
004014C7 |. E8 F0050000 call CM_含笑?00401ABC ; _创建远程线程 (窗口进程ID, 0, 0, &弹出提示信息, 0, 0, 0)
这里的Call调用时所push的参数,与DLL定义的是绝对的一致的,不像上面那个 取文本中间 () 这个函数,中间还参杂了许多其它的东西.
004014D7 |. E8 E0050000 call CM_含笑?00401ABC ; 关闭对象 (线程句柄)
004014DC |> \837D F4 11 cmp [local.3],0x11 ; 结果值 > 17
004014F6 |. E8 AF050000 call CM_含笑?00401AAA ; 作用暂时不明了
00401506 |. E8 9F050000 call CM_含笑?00401AAA ; 作用暂时不明了
至此 那个关键Call 004010B1 |. E8 43010000 call CM_含笑?004011F9 里面的逻辑已经分析完了,接下来我就讲讲其中一些Call我是如何看出来是对应易语言的哪一行代码.
持续更新中.....今天就先写到这里了.等周末看看有没有时间,再接着写点内容.
|
|