西湖论剑2023 Dual personality 复现
一点小知识:天堂之门
天堂之门是一种利用Windows的WoW机制,在32位的进程中执行64位程序代码,达到反检测的目的(反静动态分析)。
那么什么是WoW?他的全称是Windows 32 on Windows 64。众所周知,win64平台向下兼容,可以在x64平台上运行x86程序,而Windows之所以可以做到这点,就是因为使用了wow作为翻译层。而天堂之门就是利用了这个机制,在32位程序中插入64位程序代码,让逆向分析工具不能正常分析成功。同理如果我们想要让他能够被正常分析,我们也只需要找到程序中被插入的64位代码,然后将其dump出来单独分析即可。当CS = 0x23,执行32位程序;CS = 0x33,执行64位程序。天堂之门技术通过修改cs的值实现在32位程序种调用64位的代码,导致调试器出错并限制逆向人员的动静态分析。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。原文链接:https://blog.csdn.net/m0_52164435/article/details/129540631
那么这个程序是如何实现天堂之门技术的呢,在里面我们可以发现sub_401120这个函数,而我们用ida32打开并动调,执行完这个函数后,会发现程序变得非常诡异,完全不知道接下来是怎么运行的,其实这时已经进入了64位程序并执行了,但在ida32或x86dbg中都是完全无法追踪这个过程。
可以看到,在执行sub_401120前push了 0x4011D0,而这个东西就是第一个64位的指令函数地址。
这个函数sub_401120执行完后,按c键重新识别语句,会发现机器码变成:
4013E8 EA D0 11 40 00 : jmp far ptr loc_4014FE + 2 (这里应该是jmp far ptr sub_4011D0??但在32位ida里识别不出来)
4013E8 33 00
而 jmp far ptr xxxx的特性:
jmp far ptr xxxx
而且执行该jmp指令后,会修改cs,ip寄存器。 ip变为EA后的前8位,在这里即0x004011D0;cs变为EA后的后4位,这里是0x0033
而我们可以看到在新生成的指令中有0x33的字样,可以得知就是这里jmp到401120后,把cs寄存器的值改成了0x33,进入了64位程序执行模式,也就是这题的万恶之源。
接下来开始正式对题目进行流程分析:
ida打开,首先输入flag,然后经过一个sub_401120函数,通过将cs寄存器变为0x33,就可在32位程序里执行64位指令,经过这个函数后,后面的指令发生了改变,这应该是一个jmp far ptr sub_4011D0的指令。
将0x4011D0处指令dump下来,然后用ida64打开。
看看这个程序的逻辑,第一句代码应该是mov rax, gs:60h,就是获取到64位下的PEB结构,但不知道我这里为什么会显示成这样。
那么后面就是将检测是否正在调试的值存到 ds:40705Ch 处,如果检测到这个值不为0,即正在调试中,则直接跳回;如果为0,即不在调试中,则将0x5DF966AE存放在0x407058h处,以此达成反调试的效果。
然后跳回到cs:[0x40700]处,即转到0x1E000处,然后又跳回0x4013EF处。
此时将0x407058处的值拿出来,应该是0x5DF966AE,再进行接下来的运算,经过简单的分析。
第一部分的加密伪代码可表示为
uint32_t enc[8]; //四字节
int delta = 0x5DF966AE;
delta -= 0x21524111;
for(int i=0;i<8;i++)
{
enc[i] += delta;
delta ^= enc[i];
}
接着往下分析,看到call fword ptr byte_0x40700C,也就是call far ptr 0x401200,注意到byte_0x40700C后面有个0x33,也就是说又进入了64位的程序。
而0x401200处值就在dword_4011D0之中,为0xEC8B4855,再回到之前dump出来的代码,会发现这就是这个sub_30函数的开头,按p构建其函数,查看伪代码。
这个加密函数的逻辑也很简单,通过之前的分析即可得知0x40705C是存放检测调试的值,如果其值为1,即被调试中,则执行上面的假加密;否则则执行下面的真加密。
第二部分加密的伪代码:
uint64_t _ROL8_(uint64_t num,int value) //循环向左位移
{
uint64_t a, b;
value %= 64;
a = num << value;
b = num >> (64-value);
return a | b;
}
uint64_t enc[4]; //八字节
enc[0] = _ROL8_(enc[0], 12);
enc[1] = _ROL8_(enc[1], 34);
enc[2] = _ROL8_(enc[2], 56);
enc[3] = _ROL8_(enc[3], 14);
接着往下分析,又看到调用了sub_401120,下面又是一个跟第一处加密一样的套路,跳转到sub_401290,同样dump下来用ida64打开。
查看程序,发现从发现从0x407014开始每四个字节进行了一系列运算,这四个数并不是密文部分,他们是可以在进入sub_401290前截取到的,再结合下面的分析可知道这四个数是key,初始值分别为0x9D,0x44,0x37,0xB5。
因此第三部分加密伪代码为
uint32_t key[4] = {0x9D, 0x44, 0x37, 0xB5};
key[0] &= key[1];
key[1] |= key[2];
key[2] ^= key[3];
key[3] = ~key[3];
回到源程序继续分析,下面这部分仍然是64位的代码,ida32中无法识别,于是再次dump下来到ida64中查看(从0x40146F开始)。
可见引用了0x407014,即key指针,并进行了异或操作,而0x407060处正是存放密文的部分,因此这里就是个简单的单字节异或加密
第四部分的伪代码如下:
unsigned char enc[32]; //单字节
for(int i = 0;i < 32;i++)
{
enc ^= key[i % 4];
}
知道了加密流程后,那么exp就很容易得出来了,但这里涉及到一点数据类型的转换,需要稍微花点功夫
#include<iostream>
#include<stdint.h>
using namespace std;
unsigned char enc1[] =
{
0xAA, 0x4F, 0x0F, 0xE2, 0xE4, 0x41, 0x99, 0x54, 0x2C, 0x2B,
0x84, 0x7E, 0xBC, 0x8F, 0x8B, 0x78, 0xD3, 0x73, 0x88, 0x5E,
0xAE, 0x47, 0x85, 0x70, 0x31, 0xB3, 0x09, 0xCE, 0x13, 0xF5,
0x0D, 0xCA
};
uint64_t _ROR8_(uint64_t num,int value) //旋转循环位移
{
uint64_t a, b;
value %= 64;
a = num >> value;
b = num << (64-value);
return a | b;
}
int main()
{
uint32_t key[4] = {0x9D, 0x44, 0x37, 0xB5};
key[0] &= key[1];
key[1] |= key[2];
key[2] ^= key[3];
key[3] = ~key[3];
for(int i=0;i<32;i++)
{
enc1[i] ^= key[i%4];
}
uint64_t enc2[4];
for(int i=0;i<4;i++)
{
enc2[i] = *((uint64_t*)&enc1[i*8]); //单字节转8字节
}
enc2[0] = _ROR8_(enc2[0],12);
enc2[1] = _ROR8_(enc2[1],34);
enc2[2] = _ROR8_(enc2[2],56);
enc2[3] = _ROR8_(enc2[3],14);
uint32_t enc3[8];
int delta = 0x5DF966AE,tmp;
delta -= 0x21524111;
for(int i=0;i<8;i++)
{
enc3[i]=*(((uint32_t *)enc2)+i); //8字节转4字节
tmp = enc3[i];
enc3[i] -= delta;
delta = delta ^ tmp;
}
unsigned char a;
for(int i=0;i<8;i++)
{
for(int k=0;k<4;k++)
{
a = *(((unsigned char *)&enc3[i])+k); //4字节转单字节
printf("%c",a);
}
}
}
后记:
这道题从接触到完成复现前前后后快用了一个月,我记得当时做的时候快把我给搞崩溃了,没见过连动调也如此诡异的。
后来看到题解后有种恍然大悟的感觉,原来是用了天堂之门技术啊,但想着也就这样了,只是我不知道而已,没有好好地复现。
直到我昨天开始试着做,深刻领悟到什么叫“看着容易,做起来难”。这题并不只是难在天堂之门技术,还有很多我不熟悉的基础知识,这也让我有了要认真复现以前做过的题的想法,因为很多东西不是看看就会的,必须要亲手实践,这样才能让更多知识刻在脑子里。
漫长的复现计划要开始了