该程序没有壳,有三处简单的反调试,patch掉后,通过输入的检测后,会有三段解密函数来还原出一个dll,通过文件映射向dll内传递flag的密文,在dll中进行aes解密,最终得到flag。
运行一下,查看其输出结果。
首先使用Exeinfo查壳,发现没有壳,是X64的程序。
用X64dbg打开发现有地址随机化,用CFF关闭地址随机化OptionHandle->DllCharacteristics
,便于后续继续分析。
在main函数处下断点,运行后发现有弹框并退出进程,则判断有TLS反调试。
使用ida查看TLS函数处,发现有IsDebuggerPresent反调试和四个加密的数组。
手动Path掉反调试,继续分析,等待数组的内容解密后可以看到解密后的字符串。
APC注入可以让一个线程在它正常的执行路径运行之前执行一些其他的代码,每一个线程都有一个附加的APC队列,他们在线程处于可警告的时候才被处理(WaitForSingObjectEx,SleepEx)。
异步过程调用,apc可以看成就是内核里的定时器,为了给自己一个在本函数返回后还能执行的一次机会,有很多操作是需要在函数返回后才能执行.类似于析构函数但不完全是。
反反调试:跟进IsDebuggerPresent
API中,进行如下修改即可。
位置:mian函数->beginthreadex
中的线程启动函数(140009180)-> sub_140008B20。
使用快照遍历进程获取进程的md5值与原有的md5值进行判断,当存在指定进程时则退出程序,这里可以判断为反调试。
反反调试方案:patch掉exit函数即可。
md5加密的两个特征:
md5对比值
据此可以判断其为md5算法。
这里为线程启动函数中的第二个函数,里面全部都是进行反调试的代码,除了调用常见的IsDebuggerPresent
和CheckRemoteDebuggerPresent
来进行反调试,还调用了TLS解密后的函数NtQueryInformationProcess
和ZwQueryInformationThread
来进行DebugPort调试端口的判断。
反反调试:直接patch掉这个函数即可。
顺利进入到main函数,开始下一步的分析,进入sub_140009C20
函数中。
可以看到为全局变量qword_140016178
,qword_140016180
申请堆空间的操作。
跟进其中的sub_1400086C0
函数内,发现了疑似函数参数内有编号0x10001~0x10003。
依次跟进这些函数中。
这里跟进函数中的虚表的第二项可以看到对应的虚函数的地址。
跳到对应的函数地址sub_14000a8a0
去查看,发现有对原有数据进行异或的操作。
跟进去byte_1400111A0
可以看到,其为一大段数据,长度为19456,这里可能藏有一个文件。
继续分析剩下的两个sub_140008370
、sub_1400083F0
发现其结构与sub_14000a8a0
中一致,找到虚表中的虚函数地址依次跟进去。
发现其都对byte_1400111A0
数组内的数据进行了变换的操作,同时由于if判断条件的不同,各对其中的一部分数据做变换,猜测其可能为解密的函数,并与之前传入的ID可能有所关联。
退出去sub_1400086C0
函数,回到sub_140009C20
中,接着往下分析。
可以看到创建事件对象的操作,结合上述解密函数里有SetEvent设置事件对象的操作,猜测这里是为了防止重复对数据进行变换。
接着往下跟进sub_140008850
,可以看到这里获取函数地址的操作,而这几个函数的名称是在上面分析过的TLS函数中解密的。
此时第一个函数sub_140009c20分析完毕,再次回到main函数中。
可以看到其有创建线程的操作,跟进其线程启动函数StatAddress中去。
跟进去后,依次对其中的函数来进行分析。
首先进入第一个函数sub_140008B20
中去,进行分析。
可以看到其中的sub_140008300的参数为我们之前分析过的解密函数的对应序号,而其参数v7在下面sub_140006C10函数中被当作参数使用,并且其中参数还有之前看到过的qword_140016178,可以判定其与我们之前分析的疑似的解密函数必有关联。
跟进去sub_140008300函数中,发现其是将编号0x100001赋值给了a1+4的位置。
跟进去sub_140006c10
,发现其中为解密函数调用的位置(虚表函数调用),并且a3为传入参数。
查看其传入的a3参数为106,联想之前解密函数的内容,可以判断其为解密函数的“密钥”
由于之前解密函数有三个,再次进入sub_140006c10后,按X查看交叉引用,发现其调用处也有三个。
跟进去后,发现sub_140008300和sub_140006c10其为成对出现的。
分别取得其传入参数a3(密钥)的值。
其中0x100002 => 0,根据之前解密函数内分析可知,其有一个是没有参数的,正好对应了起来。
在运行此解密函数之前有个判断条件,读取了 filePath:signature
文件流,判断其内容为加密后和MD5值做比较。
其中字符串的xor解密可以编写ida Python脚本来进行解密。
对MD5值进行解密。
FCAEEB6E34B4303E99B91206BD325F2B => Overwatch
可以通过以下方式写入文件流:
把"Overwatch"字符串写入后就能通过检测。
继续寻找编号0x100003对应的密钥,可以看到在上方判断条件中有验证的函数sub_140009200
,来验证输入。
跟进sub_140009200函数内,发现其对输入进行了加密验证,还原正确的输入。
根据其算法编写对应的解密代码。
输出结果为Akira_aut0_ch3ss_!
此结果就是我们的0x10003对应的密钥了。
此时整理可得:
继续在线程启动函数中向下分析可以发现有向apc队列添加函数的操作。
跟进去其添加的函数地址sub_140009850。
可以看到其有WaitFormultipleObjects的操作,等待3个解密函数全部执行完成,之后创建了共享内存,并且申请了一段空间,将解密后的数据复制过去,并且对齐验证了PE标记,根据其创建事件时的字符串可以简单判断该加密后的文件为DLL文件,则可以猜测sub_140007D80中有LoadLibrary的操作。
查看导入表中的LoadLibrary,然后查看交叉引用,可以发现在sub_140007D80中却有引用。
由此基本可以判定sub_140007D80作为用调用DLL中的函数执行功能的操作,而被加密的数据正是DLL。
根据以上信息编写解密代码,将DLL文件解密出来。
可以看到DLL就是最终解密的主阵地了,在DLL中打开了共享内存,读取到了密文来进行解密,其中的密钥为Ak1i3aS3cre7K3y
。
ida中使用FindCrypto插件可以进行识别,但是发现ida7.5中装不上该插件,所以这里使用HashCryptoDetector来进行识别。
通过CFF来进行FOA=>VA的转换。
在Ida中按G键跳转过去,查看交叉引用,可以看到在函数sub_180001000中有对其的使用。
在函数180001000头部查看交叉引用,依次回溯可以最终确定到是在sub_180002800处进行的调用,根据其参数则可以判定sub_180002800为AES加密函数。
回溯过程如下:1800041e0=>sub_180001000=>sub_1800013D0=>sub_180002800
根据分析结果对其在共享内存中传递的密文使用密钥Ak1i3aS3cre7K3y
进行解密。
将其转换为base64.
在线解密得到flag值。
最后的flag值为flag{Ak1rAWin!}
https://xz.aliyun.com/t/6042#toc-9
https://blog.csdn.net/qq_41252520/article/details/100738585
https://bbs.pediy.com/thread-255081.htm
在解题过程中学习到了ida Python脚本的编写和加密函数的识别。
有兴趣的小伙伴可以下载题目来进行复现。
若文中有错误,望留言告知,感谢各位前辈。
BEGIN
=
0x140015ee0
len
=
0x16
for
i
in
range
(
len
):
tmp
=
Byte(BEGIN
+
i)
tmp
=
tmp ^
0x0c1
PatchByte(BEGIN
+
i, tmp)
BEGIN
=
0x140015ee0
len
=
0x16
for
i
in
range
(
len
):
tmp
=
Byte(BEGIN
+
i)
tmp
=
tmp ^
0x0c1
PatchByte(BEGIN
+
i, tmp)
sub_140007DD0(
Buffer
, v0, (__int64)v10);
v8[
0
]
=
0xFC
;
v8[
1
]
=
0xAE
;
v8[
2
]
=
0xEB
;
v8[
3
]
=
0x6E
;
v8[
4
]
=
0x34
;
v8[
5
]
=
0xB4
;
v8[
6
]
=
0x30
;
v8[
7
]
=
0x3E
;
v8[
8
]
=
0x99
;
v8[
9
]
=
0xB9
;
v8[
10
]
=
0x12
;
v8[
11
]
=
6
;
v8[
12
]
=
0xBD
;
qmemcpy(v9,
"2_+"
, sizeof(v9));
sub_140007DD0(
Buffer
, v0, (__int64)v10);
v8[
0
]
=
0xFC
;
v8[
1
]
=
0xAE
;
v8[
2
]
=
0xEB
;
v8[
3
]
=
0x6E
;
v8[
4
]
=
0x34
;
v8[
5
]
=
0xB4
;
v8[
6
]
=
0x30
;
v8[
7
]
=
0x3E
;
v8[
8
]
=
0x99
;
v8[
9
]
=
0xB9
;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-3-9 17:14
被flag0编辑
,原因: 有遗漏