由于之前没搞过python的,直接百度下相关内容了解到以下两个信息
了解以上两个信息后,打开OD调试,在IDA中通过交叉引用
找到GetProcessAddress后的函数地址的call调用处
对其下断点,运行发现断不下来!!!
OD中ctrl+F2重新运行
,发现了个奇怪的现象,之前的程序窗口没有被关闭,就又开了一个新进程。于是,关掉所有crackme, 打开任务管理器,重新运行cm,看到出现了两个进程
在IDA导入表中查找CrateProcess
, 可以看到程序使用的是CreateProcessW
, OD中使用bp CreateProcessW
对其下断运行
这里发现没有额外的命令行参数,并且在IDA中可以看到,CreateProcess之后,进程1就在WaitForSingleObject
了,所以python相关的代码应该全部在进程2中执行,那么怎么调试进程2呢?
由于进程1没有使用调试模式来创建进程2,所以在进程2被创建成功后,使用od附加是可以成功附加的,但是这个时候附加已经过了python脚本的加载时机了,需要更早一些才行,所以我这里采用修改CC来触发异常给调试器接管。
考虑到GetProcessAddress之用后这些函数才正式开始使用,所以我找的是执行了GetProcessAddress函数之后的sub_403E10
函数,这个函数里可以看到有Py_SetProgramName
,Py_Initialize
等初始化设置的函数,所以我选择在sub_403E10
处修改0x56为0xCC
修改完成后直接运行CM,触发CC直接断在进程2的0x403E10处要设置OD为默认的实时调试器
单步跟看到这样一个路径0022CE90 00416140 UNICODE "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\_MEI33682\base_"
找过去看了下,是一些python的运行环境,并没有关键的东西,继续跟代码。
这里添加了__main__
,看来下面就快要到调用__main__
函数的地方了, 继续跟代码, 就在下方不远处有一个小循环
这个一直在查找[ebx+0x11]
处等于0x73
的结果,查看EBX
对应的地址发现有这样一个表
简单推测可知道开头4个字节
为每一项的长度,0x11
偏移处为字符串起始,0x73是s
, 以s开头的有spyiboot01_bootstrap
和 sKERNEL32.dll
找到一个后就去打开自身,从自身0x1F000 + offset
处读取数据,解压数据,执行。最终分析的这个表的结构是|长度|偏移|大小|解压后大小|名字|
解压后的数据就是pyc,只不过被抹去了前12字节,抹去的前12字节主要的是前4字节Magic Number
打开自身
读取padding信息(数据为压缩过的)
解压使用的是zlib
库,版本1.2.8,可根据代码中的错误提示字符串搜索得到。
C代码的执行的逻辑到这就结束了,因为程序运行起来看到的界面都是在python中执行的,后面就说下怎么获取并反编译pyc
下面這包是用 python 3.4,一樣可以查表
或是利用 archive_viewer.py 顯示前幾包的內容,開頭的 4 bytes 就是 magic number
'EE 0C 0D 0A'
在sKERNEL32.dll.pyc最前面添加 EE 0C 0D 0A XX XX XX XX XX XX XX XX 十二个字节,注意是添加不是修改
我一开始是修改了开头的12字节,结果导致Easy Python Decompiler无法还原,后来在这个帖子里
https://stackoverflow.com/questions/21067313/how-convert-and-save-python-module-from-pyobject-as-binary-data-to-use-it-lat 看到一段代码
这里减8 是因为是python2.7 只有前8字节是magic value
, 而3.4是前12字节
补上12字节的magic value后直接拖到Easy Python Decompiler就能看到python代码了,如下
代码看起来有些问题,先注释掉while后面的用python运行下看看,注意运行环境是python3.x
看到了这个界面,看来这就是验证的地方,仔细阅读下while循环中的代码,得知z4是输入且长度为10,z1用来验证输入的有效性,
可知key的长度为10且由0-9,a-f组成
,str(int(z4, 16))用来把输入的16进制串转为10进制串。
关键的判断点是if hashlib.md5(z3.encode('utf-8')).hexdigest() == b(m5, 239)
所以算法就是判断输入的值转10进制字符串后的md5是否与预设值相等,将b(m5, 239)放在前面直接print得到md5为524b38df7fe44db9f9b6621f14550e55
代码中其实还有smc, 最终运行的python脚本与文件里保存的有一点区别,修改代码的函数是sub_407CC0
这里有个有趣的事情,下面这段代码如果单步运行,那么最后不会修改python代码,直接走free,如果在这段代码之后下断点直接run过去,就会多走修改python代码的处理,经过几次单步感觉是pop ss
影响了push fd
的执行,nop
掉push ss
和pop ss
就能单步跟到smc处
smc代码
所以最终修改后的代码应该在0x1c5处比原始的小 1 ,用比较软件打开内存dump的代码和文件中解压出来的代码可以看到确实只有此处是不同的
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课