isgoodtime 发表于 2017-8-30 15:59

适合新手练手的无壳无加密易语言静态编译CrackMe程序,持续更新逆向分析过程(非常详细)

本帖最后由 isgoodtime 于 2017-9-15 14:55 编辑

从来没发过CM,KM,第一次发,无壳无加密,只少量诱骗+字符串隐藏,易语言程序

验证算法超级简单.只简单的验证注册码和注册名的一些规则,并无任何加密算法.

为什么自己认为有点难破...主要还是因为...等以后再公布方法吧.也许在各位看官面前不值一提.


已破,嘿,附上源码及原理,给大家练手.适合新手.

isgoodtime 发表于 2017-9-5 15:02

本帖最后由 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 )
inc 后面是local.3 ,local 就是本地的意思嘛,我个人理解, local.3就是本地变量3,然后我回过头去数那些变量,发现好像那个是在第三个耶.如下图.



这里简单介绍一下那个 local.3 是怎么来的,因为这里的原始代码其实是这样的 00401352    FF45 F4         inc dword ptr ss:
要怎么看呢,如下图,右键菜单中的分析-->从模块中删除分析,咱们就可以看到原始代码了,想还是看到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 ,eax ;最终将拼接好的字节集赋值给 (上面初始化变量得出是易语言的局部变量 硬盘特征码,)
004012FA|.E8 C9070000   call CM_含笑?00401AC8 ;此处Call作用不明
00401311|.E8 94070000   call CM_含笑?00401AAA ;取数据摘要 (硬盘特征码)
0040131A|.8945 F8       mov ,eax;把获取出来的数据摘要赋值给 (上面初始化变量得出是易语言的局部变量 特征码MD5值)

00401324|.8B5D 0C       mov ebx,
00401327|.8B03          mov eax,dword ptr ds:
00401329|.85C0          test eax,eax
;这三行是检测(输入的注册码)是否为空,(arg.2 argument.2的简写,argument就是参数的意思.还是老样子与代码对应得上)
;从这三行来看易语言编译后的代码有点啰嗦,明明两行可以搞定为什么要三行呢?有没有高人指点一下.
;是真的啰嗦呢还是有别的什么好处.

0040132B|. /75 05         jnz short CM_含笑?00401332 ;这行代码是接着上面那个检测非空来的,这里很有意思...如果为空的话,会赋予一串奇怪的字符
0040133D|.E8 6E070000   call CM_含笑?00401AB0 ;取文本长度 (输入的注册码)
00401348|.837D E0 19    cmp ,0x19 ;找到了就是这里如果大于0x19
00401352|.FF45 F4       inc ;然后就把伪结果+1
00401374|.8B45 F8       mov eax,
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,
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 以及
00401374mov eax,
,刚好与易语言代码的 取文本中间 (特征码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 ;结果值 = 结果值 + 1
00401428|> \FF4D F4       dec ;结果值 = 结果值 - 1
00401430|> \FF4D F4       dec ;结果值 = 结果值 - 1

00401433|> \FF75 0C       push ;接下来三行,很明显
00401436|.FF75 08       push ;连续传了两个 ,
00401439|.E8 42010000   call CM_含笑?00401580 ;将名字和注册传至验证程序 (输入的名字, 输入的注册码)


好好好...下面的代码分析着分析着我突然...发现了一个问题,就是之前咱们学习的东西有点问题.
前面咱们说的 变量的位置与 看下面这个截图...原来之前咱们意淫的观点不正确...
看来每次学习新知识,除了要会意淫(猜测),还得动手验证一下观点正不正确.否则后果不堪设想.



从这张图片可以看出来...之前上面咱们所理解的, 就是第几个参数.是错误的,这里明显反的对不对.还好这里有个常数0x1F0FF,要不是有这个常数...我也会迷迷糊糊的把这个问题给带过去了.因为有常数值的时候,看着看着,才发现用之前的那个按变量顺序编号的方法有点问题.

但这里我再先意淫一次,从这里来看,好像是变量在代码谁先出现,就是谁排在第一,虽然现在是意淫,等会我会再去写一个易语言测试程序,来验证一下这个意淫出来的观点.
好啦好啦 ,再接着把下面几个Call的功能都列出来,全列完之后,我就来说我是怎么知道这些Call是对应易语言里面的那一行代码的.

00401457|.E8 54060000   call CM_含笑?00401AB0 ;取窗口句柄()
0040146E|.E8 49060000   call CM_含笑?00401ABC ;从下一行的 可以看,这一行是 取窗口进程ID (取窗口句柄 (), 程序进程ID)
00401473|.837D F0 00    cmp ,0x0 ;如果真 (程序进程ID ≠ 0)
00401485|.68 FF0F1F00   push 0x1F0FFF ;从这个立即数0x1F0FF=2035711可以看出,下面是调用打开进程
0040148F|.E8 28060000   call CM_含笑?00401ABC ;打开进程 (2035711, 0, 程序进程ID)
00401497|.837D EC 00    cmp ,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
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 ,0x11 ;结果值 > 17
004014F6|.E8 AF050000   call CM_含笑?00401AAA ;作用暂时不明了
00401506|.E8 9F050000   call CM_含笑?00401AAA ;作用暂时不明了

至此 那个关键Call004010B1|.E8 43010000   call CM_含笑?004011F9里面的逻辑已经分析完了,接下来我就讲讲其中一些Call我是如何看出来是对应易语言的哪一行代码.

持续更新中.....今天就先写到这里了.等周末看看有没有时间,再接着写点内容.

zbnysjwsnd8 发表于 2017-9-8 20:15

isgoodtime 发表于 2017-9-1 13:41
其实发了这么几天了...我就想知道到底分析起来有没有难度.我虽然自己写的源码...但感觉放到OD里面就找不着 ...

HANDLE WINAPI CreateRemoteThread(
        __in HANDLE hProcess,
        __in LPSECURITY_ATTRIBUTES lpThreadAttributes,
        __in SIZE_T dwStackSize,
        __in LPTHREAD_START_ROUTINE lpStartAddress,
        __in LPVOID lpParameter,
        __in DWORD dwCreationFlags,
        __out LPDWORD lpThreadId
);
第四个参数lpStartAddress就暴露了。

zenaiwen 发表于 2017-8-30 16:12

zbnysjwsnd8 发表于 2017-8-30 17:10

aaaaa/_KaQqi
1234567890abadefgijkl

钢铁侠_123 发表于 2017-8-30 18:08

zbnysjwsnd8 发表于 2017-8-30 17:10
aaaaa/_KaQqi
1234567890abadefgijkl

牛.............

明月心 发表于 2017-8-30 18:41

本帖最后由 明月心 于 2017-8-30 19:13 编辑

支持楼主,附上爆破 破解补丁一枚{:17_1066:}

苏紫方璇 发表于 2017-8-30 19:56

0000aSuZi
1234567890abadefghijk
NAME第五位和KEY第13位是a就行key长度是21

SomnusXZY 发表于 2017-8-31 16:14


0000aSuZi
1234567890abadefghijk
NAME第五位和KEY第13位是a就行key长度是21

ss63551234ss 发表于 2017-8-31 20:29

不错不错。确实不难

isgoodtime 发表于 2017-9-1 13:41

本帖最后由 isgoodtime 于 2017-9-9 18:11 编辑

其实发了这么几天了...我就想知道到底分析起来有没有难度.我虽然自己写的源码...但感觉放到OD里面就找不着北了....这个思路还是以前无意中发现CreateRemoteThread跟进去会到系统领空,会误导分析思路.当SuZi把算法都分析出来了的时候...我感觉特别的不可思议...那么请问,那些大神们是怎么做到的....
页: [1] 2
查看完整版本: 适合新手练手的无壳无加密易语言静态编译CrackMe程序,持续更新逆向分析过程(非常详细)