一
基础知识
1.1 在x64下的进程
cs
段寄存器。cs
段寄存器的,所以只要修改cs
的值,就能实现切换,再使用retf
指令回到xx位。1.2 WoW64
syscall
orcall
以及jmp far ptr
orcall far ptr
实现跨位运行。二
WoW64实现过程
ntdll.dll
中的32位函数。ntdll.dll
调用wow64cpu.dll
中的X86SwitchTo64BitMode
,就是调用该函数后进程从32位模式切换到64位模式,wow64.dll
将32位的系统调用转化为64位。ntdll.dll
中的64位函数。2.1 转换过程参考
retf
是切换32位和64位的关键指令。// x86 to x64
6A 33 ; push 0x33 ; 将值 0x33 压入栈顶(此值将用于修改 CS 段寄存器)
E8 00 00 00 00 ; call $+5 ; 将下一条指令的地址(即当前 EIP+5)压入栈中,并继续执行下一条指令
83 04 24 05 ; add dword [esp], 5 ; 修改栈顶的返回地址,将其增加 5,指向 `retf` 之后的下一条指令
CB ; retf ; 通过 `retf`(返回并修改段寄存器),使程序跳转到返回地址,同时将 `CS` 段寄存器修改为 0x33,切换到 64 位模式
// x64 to x86
E8 00 00 00 00 ; call $+5 ; 将下一条指令的地址(即当前 RIP+5)压入栈中,并继续执行下一条指令
C7 44 24 04 23 00 00 00 ; mov dword [rsp + 4], 0x23 ; 将栈中返回地址的高 32 位修改为 0x23,指示程序返回时切换到 32 位模式
83 04 24 0D ; add dword [rsp], 0xD ; 修改栈顶的返回地址,将其增加 0xD,指向 `retf` 之后的下一条指令
CB ; retf ; 通过 `retf`,程序跳转回 32 位模式,并继续执行跳转后的代码
2.2 Test
#include "stdio.h"
#include "windows.h"
#include "Shlobj.h"
#include "tchar.h"
#pragma comment(lib, "Shell32.lib")
int _tmain(int argc, TCHAR* argv[])
{
HKEY hKey = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
TCHAR szPath[MAX_PATH] = { 0, };
////////////////
// system32 folder
if (GetSystemDirectory(szPath, MAX_PATH))
{
_tprintf(L"1) system32 path = %sn", szPath);
}
////////////////
// File size
_tcscat_s(szPath, L"\kernel32.dll");
hFile = CreateFile(szPath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
_tprintf(L"2) File size of "%s" = %dn",
szPath, GetFileSize(hFile, NULL));
CloseHandle(hFile);
}
////////////////
// Program Files
if (SHGetSpecialFolderPath(NULL, szPath,
CSIDL_PROGRAM_FILES, FALSE))
{
_tprintf(L"3) Program Files path = %sn", szPath);
}
////////////////
// Registry
if (ERROR_SUCCESS == RegCreateKey(HKEY_LOCAL_MACHINE,
L"SOFTWARE\ReverseCore", &hKey))
{
RegCloseKey(hKey);
_tprintf(L"4) Create Registry Key : HKLM\SOFTWARE\ReverseCoren");
}
return 0;
}
三
CTF运用
月饼杯2 EasyTea
3.1 分析天堂之门部分
unsigned int dword_427A30[8] = {
0xB5ABA743, 0x4C5B3EE0, 0xB70AEB14, 0x6946BC13, 0x906089C4, 0x5B9F98F0, 0x0964B652, 0x78920976
};
.text:00401258 FF 55 B4 call dword ptr [ebp-4Ch]
// 倒着看回去,追踪[ebp-4c]
.text:00401240 8B 45 DC mov eax, [ebp+var_24]
.text:00401243 89 45 B4 mov [ebp+var_4C], eax
// 通过eax作为媒介,追踪到[ebp+var_24]
.text:004011D1 C7 45 DC 50 7A 42 00 mov [ebp+var_24], offset unk_427A50
// 继续追踪,发现关键函数unk_427A50
3.2 解题
unk_427A50
dump出来,patch到随意的64位程序中。# include<stdio.h>
int main()
{
printf("Hello world!n");
return 0;
}
// 现写一个hello world代码
// gcc version 13.2.0 (GCC)
// gcc -o test test.c编译为64位程序
dump_data = [0x48, 0x89, 0x4C, 0x24, 0x08, 0x55, 0x57, 0x48, 0x81, 0xEC,
0xA8, 0x01, 0x00, 0x00, 0x48, 0x8D, 0x6C, 0x24, 0x20, 0x48,
0x8B, 0xFC, 0xB9, 0x6A, 0x00, 0x00, 0x00, 0xB8, 0xCC, 0xCC,
0xCC, 0xCC, 0xF3, 0xAB, 0x48, 0x8B, 0x8C, 0x24, 0xC8, 0x01,
0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0xC7, 0x45, 0x08, 0x66, 0x00, 0x00,
0x00, 0xC7, 0x45, 0x0C, 0x6C, 0x00, 0x00, 0x00, 0xC7, 0x45,
0x10, 0x61, 0x00, 0x00, 0x00, 0xC7, 0x45, 0x14, 0x67, 0x00,
0x00, 0x00, 0xC7, 0x45, 0x18, 0x69, 0x00, 0x00, 0x00, 0xC7,
0x45, 0x1C, 0x73, 0x00, 0x00, 0x00, 0xC7, 0x45, 0x20, 0x6D,
0x00, 0x00, 0x00, 0xC7, 0x45, 0x24, 0x65, 0x00, 0x00, 0x00,
0xB8, 0x04, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x07, 0x48,
0x8B, 0x8D, 0xA0, 0x01, 0x00, 0x00, 0x8B, 0x04, 0x01, 0x89,
0x45, 0x44, 0xC7, 0x45, 0x64, 0x00, 0x00, 0x00, 0x00, 0xC7,
0x85, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB,
0x0E, 0x8B, 0x85, 0x84, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x89,
0x85, 0x84, 0x00, 0x00, 0x00, 0x83, 0xBD, 0x84, 0x00, 0x00,
0x00, 0x20, 0x0F, 0x8D, 0x44, 0x01, 0x00, 0x00, 0x8B, 0x45,
0x64, 0x05, 0x45, 0x11, 0x48, 0x88, 0x89, 0x45, 0x64, 0xC7,
0x85, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB,
0x0E, 0x8B, 0x85, 0xA4, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x89,
0x85, 0xA4, 0x00, 0x00, 0x00, 0x83, 0xBD, 0xA4, 0x00, 0x00,
0x00, 0x07, 0x0F, 0x8D, 0x8A, 0x00, 0x00, 0x00, 0x48, 0x63,
0x85, 0xA4, 0x00, 0x00, 0x00, 0x8B, 0x8D, 0xA4, 0x00, 0x00,
0x00, 0xFF, 0xC1, 0x48, 0x63, 0xC9, 0x48, 0x8B, 0x95, 0xA0,
0x01, 0x00, 0x00, 0x8B, 0x0C, 0x8A, 0xC1, 0xE1, 0x04, 0x8B,
0x95, 0xA4, 0x00, 0x00, 0x00, 0xFF, 0xC2, 0x48, 0x63, 0xD2,
0x4C, 0x8B, 0x85, 0xA0, 0x01, 0x00, 0x00, 0x41, 0x8B, 0x14,
0x90, 0xC1, 0xFA, 0x05, 0x33, 0xCA, 0x8B, 0x95, 0xA4, 0x00,
0x00, 0x00, 0xFF, 0xC2, 0x48, 0x63, 0xD2, 0x4C, 0x8B, 0x85,
0xA0, 0x01, 0x00, 0x00, 0x41, 0x03, 0x0C, 0x90, 0x8B, 0x55,
0x64, 0x83, 0xE2, 0x07, 0x8B, 0xD2, 0x8B, 0x54, 0x95, 0x08,
0x44, 0x8B, 0x45, 0x64, 0x44, 0x03, 0xC2, 0x41, 0x8B, 0xD0,
0x33, 0xCA, 0x48, 0x8B, 0x95, 0xA0, 0x01, 0x00, 0x00, 0x03,
0x0C, 0x82, 0x8B, 0xC1, 0x48, 0x63, 0x8D, 0xA4, 0x00, 0x00,
0x00, 0x48, 0x8B, 0x95, 0xA0, 0x01, 0x00, 0x00, 0x89, 0x04,
0x8A, 0xE9, 0x5B, 0xFF, 0xFF, 0xFF, 0xB8, 0x04, 0x00, 0x00,
0x00, 0x48, 0x6B, 0xC0, 0x07, 0xB9, 0x04, 0x00, 0x00, 0x00,
0x48, 0x6B, 0xC9, 0x00, 0x48, 0x8B, 0x95, 0xA0, 0x01, 0x00,
0x00, 0x8B, 0x0C, 0x0A, 0xC1, 0xE1, 0x04, 0xBA, 0x04, 0x00,
0x00, 0x00, 0x48, 0x6B, 0xD2, 0x00, 0x4C, 0x8B, 0x85, 0xA0,
0x01, 0x00, 0x00, 0x41, 0x8B, 0x14, 0x10, 0xC1, 0xFA, 0x05,
0x33, 0xCA, 0xBA, 0x04, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xD2,
0x00, 0x4C, 0x8B, 0x85, 0xA0, 0x01, 0x00, 0x00, 0x41, 0x03,
0x0C, 0x10, 0x8B, 0x55, 0x64, 0x83, 0xE2, 0x07, 0x8B, 0xD2,
0x8B, 0x54, 0x95, 0x08, 0x44, 0x8B, 0x45, 0x64, 0x44, 0x03,
0xC2, 0x41, 0x8B, 0xD0, 0x33, 0xCA, 0x48, 0x8B, 0x95, 0xA0,
0x01, 0x00, 0x00, 0x03, 0x0C, 0x02, 0x8B, 0xC1, 0xB9, 0x04,
0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9, 0x07, 0x48, 0x8B, 0x95,
0xA0, 0x01, 0x00, 0x00, 0x89, 0x04, 0x0A, 0xE9, 0xA1, 0xFE,
0xFF, 0xFF, 0x48, 0x8D, 0x4D, 0xE0, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x48, 0x8D,
0xA5, 0x88, 0x01, 0x00, 0x00, 0x5F, 0x5D, 0xC3]
start_addr = 0x1400060C0
end_addr = start_addr + len(dump_data)
for i in range(start_addr, end_addr):
idc.patch_byte(i, dump_data[i - start_addr])
__int64 __fastcall _data_end__(int *a1)
{
char *v1; // rdi
__int64 i; // rcx
__int64 result; // rax
char v4; // [rsp+0h] [rbp-20h] BYREF
int v5[23]; // [rsp+28h] [rbp+8h]
int v6; // [rsp+84h] [rbp+64h]
int j; // [rsp+A4h] [rbp+84h]
int k; // [rsp+C4h] [rbp+A4h]
v1 = &v4;
for ( i = 106i64; i; --i )
{
*(_DWORD *)v1 = -858993460;
v1 += 4;
}
v5[0] = 102;
v5[1] = 108;
v5[2] = 97;
v5[3] = 103;
v5[4] = 105;
v5[5] = 115;
v5[6] = 109;
v5[7] = 101;
result = (unsigned int)a1[7];
v5[15] = a1[7];
v6 = 0;
for ( j = 0; j < 32; ++j )
{
v6 -= 2008542907;
for ( k = 0; k < 7; ++k )
a1[k] += (v5[v6 & 7] + v6) ^ (a1[k + 1] + ((a1[k + 1] >> 5) ^ (16 * a1[k + 1])));
a1[7] += (v5[v6 & 7] + v6) ^ (*a1 + ((*a1 >> 5) ^ (16 * *a1)));
result = (unsigned int)(j + 1);
}
return result;
}
3.3 EXP
#include <stdio.h>
void re_xxtea(int *cipher, int *key)
{
int delta = 0x77B7EEBB;
int sum = -(delta * 32);
int j, k = 6;
for (j = 0; j < 32; j++)
{
cipher[7] -= (key[sum & 7] + sum) ^ (*cipher + ((*cipher >> 5) ^ (16 * *cipher)));
for (k = 6; k >= 0; k--)
{
cipher[k] -= (key[sum & 7] + sum) ^ (cipher[k + 1] + ((cipher[k + 1] >> 5) ^ (16 * cipher[k + 1])));
}
sum += 0x77B7EEBB;
}
}
int main()
{
int cipher[] = {0xB5ABA743, 0x4C5B3EE0, 0xB70AEB14, 0x6946BC13, 0x906089C4, 0x5B9F98F0, 0x0964B652, 0x78920976};
int key[8];
key[0] = 102;
key[1] = 108;
key[2] = 97;
key[3] = 103;
key[4] = 105;
key[5] = 115;
key[6] = 109;
key[7] = 101;
re_xxtea(cipher, key);
printf("%s", cipher);
}
// Tea_12345_12345_yes_flag_is_easy
3.4 总结
32位程序
|
V
把64位函数藏在天堂之门实现处(看汇编)
|
V
因为天堂之门的存在,干扰了IDA分析逻辑,需要通过机器码来手动分析,找到cmp函数
|
V
想办法还原64位函数的内容
四
杂谈
可能有某些地方理解的不是很到位,若有问题,敬请指教!
恶意程序。
看雪ID:Sh4d0w
https://bbs.kanxue.com/user-home-1002267.htm
# 往期推荐
2、恶意木马历险记
原文始发于微信公众号(看雪学苑):天堂之门(WoW64技术)总结及CTF中的分析