准备
环境:Windows10
工具:ExeinfoPE、upx、IDA、x32dbg、010Editor
开始
附件是.exe文件,使用ExeinfoPE查看文件信息
能看出来此文件被upx加了壳。
使用upx脱壳
将脱壳后的文件放入IDA静态分析
main函数:
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+4h] [ebp-804h] BYREF
char v5[1023]; // [esp+5h] [ebp-803h] BYREF
char v6; // [esp+404h] [ebp-404h] BYREF
char v7[1023]; // [esp+405h] [ebp-403h] BYREF
v6 = 0;
memset(v7, 0, sizeof(v7));
v4 = 0;
memset(v5, 0, sizeof(v5));
printf("please input code:");
scanf("%s", &v6);
sub_401000(&v6);
if ( !strcmp(&v4, "DDCTF{reverseME}") )
printf("You've got it!!%s\n", &v4);
else
printf("Try again later.\n");
return 0;
}
逻辑分析,我们输入flag到v6中,然后v6经过sub_401000()函数操作后,比较v4和DDCTF{reverseME}是否相同,是则输入正确。
问题1:flag输入到了v6中,后来却用v4去比较。
sub_401000()函数:
unsigned int __cdecl sub_401000(const char *a1)
{
_BYTE *v1; // ecx
unsigned int v2; // edi
unsigned int result; // eax
const char *v4; // ebx
v2 = 0;
result = strlen(a1);
if ( result )
{
v4 = (const char *)(a1 - v1);
do
{
*v1 = byte_402FF8[(char)v1[(_DWORD)v4]];
++v2;
++v1;
result = strlen(a1);
}
while ( v2 < result );
}
return result;
}
关键就在sub_401000()函数,第一句
_BYTE *v1; // ecx
查看汇编代码
将ecx中的数据压入了堆栈,再往前看,查看调用sub_401000()函数函数之前的最后一次对ecx的操作语句
结合v4、v5、v6、v7的地址
可以看出在sub_401000()函数中,v1就是main函数中的v4
下面这一句就将main函数里的v6和v4联系起来了,v6中的内容作变换之后的结果放入了v4中
*v1 = byte_402FF8[(char)v1[(_DWORD)v4]];
// v1[v4]=*(v1+v4)=*(v1+a1-v1)=*(a1)=a1[0]
查看数据byte_402FF8的内容
发现是不确定的,可能是要在程序运行过程中生成的。
之前用upx把文件脱壳过后,现在的文件是无法运行的(win7也一样),而在xp系统上可以,因为win10系统采用了地址随机化(aslr),需要手动修改。
使用010Editor打开
使用EXE.bt模板,找到
struct IMAGE_NT_HEADERS NTHeader->struct IMAGE_OPTIONAL_HEADER OptionalHeader
->struct DLL CHARACTERISTICS DllCharacteristics
修改WORD IMAGE DLLCHARACTERISTICS DYNAMIC BASE为0即可。
将文件放入x32dbg中调试,断点打到sub_401000()函数执行结束
运行,scanf时随便输入,遇到sub_401000()函数直接F8步过,运行到断点处
现在查看数据byte_402FF8的内容
复制下来
00 00 00 00 00 00 00 00 87 F6 DE 58 78 09 21 A7 FF FF FF FF FF FF FF FF FE FF FF FF
01 00 00 00 7E 7D 7C 7B 7A 79 78 77 76 75 74 73 72 71 70 6F 6E 6D 6C 6B 6A 69 68 67
66 65 64 63 62 61 60 5F 5E 5D 5C 5B 5A 59 58 57 56 55 54 53 52 51 50 4F 4E 4D 4C 4B
4A 49 48 47 46 45 44 43 42 41 40 3F 3E 3D 3C 3B 3A 39 38 37 36 35 34 33 32 31 30 2F
2E 2D 2C 2B 2A 29 28 27 26 25 24 23 22 21 20 00 01 00 00 00 80 1E 9F 00 C0 18 9F 00
根据变换过程写解密脚本
hex = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xF6, 0xDE, 0x58, 0x78, 0x09, 0x21, 0xA7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59,
0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x1E, 0x9F, 0x00, 0xC0, 0x18, 0x9F, 0x00]
s = 'DDCTF{reverseME}'
flag = ''
for i in range(len(s)):
flag += chr(hex[ord(s[i])])
print('flag{'+flag+'}')
运行得flag
flag{ZZ[JX#,9(9,+9QY!}