为深入贯彻落实习近平总书记关于网络强国的重要思想,全面践行总体国家安全观,充分调动社会力量积极性,挖掘和选拔网络安全实战化人才,进一步筑牢网络安全防线,在前三届“网鼎杯”网络安全大赛基础上,第四届“网鼎杯”网络安全大赛以“网数融合,鼎筑未来”为主题,打造最大规模、最新技术、最高水平的“网络安全奥运会”。
网站链接:https://www.wangdingcup.com/#/
(能源、电力、化工、国防及其他行业单位)
文件名: | ReMe.exe |
编译器: | Microsoft Visual C/C++(16.00.30319)[LTCG/C++] |
大小: | 499.00KB |
操作系统: | Windows(XP)[I386, 32位, Console] |
架构: | 386 |
模式: | 32 位 |
类型: | EXEC |
字节序: | LE |
MD5: | 4fd22bc6938254c2ba65fcc38f23d603 |
SHA1: | b388453c3a4aa0d3142ecebf4eb9637e6b9d559c |
SHA256: | c2964f90a0d4ef70e0092aed526c482d9ab157ee3f59a40955f3e1087fbeee07 |
flag.txt
加密文件名 = 原始文件名+.cry ,例如:flag.txt.cry
文件加密使用了AES-ECB加密算法。
key内置于文件中
拖入die,发现是一个vmp保护的程序
拖入ida中,发现了一个跟堆栈保护相关的函数,通过他我们可以跟踪到入口点
通过交叉引用最后能找到,猜测此处为入口点
此处为跳转的入口点的地方
拖入xdbg,并在此处下硬件断点
断住之后使用sycall插件修复iat并转储文件
将其拖入ida中,最后出现了三个函数
第一个函数如下,首先自解密出字符串
memset(Buffer, 0, sizeof(Buffer));
for ( i = 0; i < strlen(LibFileName); ++i )
LibFileName[i] ^= 1u;
LibraryA = LoadLibraryA(LibFileName);
for ( j = 0; j < strlen(aBsdUdghmd); ++j )
aBsdUdghmd[j] ^= 1u;
Buffer[0] = (int)GetProcAddress(LibraryA, aBsdUdghmd);
for ( k = 0; k < strlen(aSdEghmd); ++k )
aSdEghmd[k] ^= 1u;
Buffer[1] = (int)GetProcAddress(LibraryA, aSdEghmd);
for ( m = 0; m < strlen(aVshudghmd); ++m )
aVshudghmd[m] ^= 1u;
Buffer[2] = (int)GetProcAddress(LibraryA, aVshudghmd);
for ( n = 0; n < strlen(aBmnrdiOemd); ++n )
aBmnrdiOemd[n] ^= 1u;
Buffer[3] = (int)GetProcAddress(LibraryA, aBmnrdiOemd);
for ( ii = 0; ii < strlen(aEdmdudghmd); ++ii )
aEdmdudghmd[ii] ^= 1u;
Buffer[4] = (int)GetProcAddress(LibraryA, aEdmdudghmd);
for ( jj = 0; jj < strlen(String2); ++jj )
String2[jj] ^= 1u;
lstrcpyA((LPSTR)&Buffer[5], String2);
memset(pszPath, 0, sizeof(pszPath));
得到如下字符串
检测当前进程是否运行在wow模式,并尝试获取系统文件夹路径
Wow64Process = 0;
CurrentProcess = GetCurrentProcess();
IsWow64Process(CurrentProcess, &Wow64Process);
SHGetFolderPathA(0, 4 * Wow64Process + 37, 0, 0, pszPath);
得到如下字符串
自解密后拼接生成字符串C:\\Windows\\SysWOW64\\svchost.exe
for ( kk = 0; kk < strlen(aRwbinruDyd); ++kk )
aRwbinruDyd[kk] ^= 1u;
lstrcatA(pszPath, aRwbinruDyd);
创建进程svchost.exe并进行注入
if ( CreateProcessA(0, pszPath, 0, 0, 0, 4u, 0, 0, v11, v13) )
{
v14 = (char *)VirtualAllocEx(v13->hProcess, 0, 0x2000u, 0x3000u, 0x40u);
if ( v14
&& (!WriteProcessMemory(v13->hProcess, v14, Buffer, 0x34u, &NumberOfBytesWritten)
|| !WriteProcessMemory(
v13->hProcess,
v14 + 52,
sub_6E14E0,
(char *)sub_6E15F0 - (char *)sub_6E14E0,
&NumberOfBytesWritten)) )
{
GetLastError();
return VirtualFree(v14, 0x2000u, 0x4000u);
}
}
else
{
v14 = (char *)NumberOfBytesWritten;
}
RemoteThread = CreateRemoteThread(v13->hProcess, 0, 0, (LPTHREAD_START_ROUTINE)(v14 + 52), v14, 0, 0);
return WaitForSingleObject(RemoteThread, 0xFFFFFFFF);
}
对v13->hProcess 指向的进程进行附加,并跳转到WriteProcessMemory注入内存的位置
得到一个字符串
对文件进行读取,同时对文件内容进行异或0x9
int __stdcall sub_B30034(int a1)
{
int (__stdcall *CreateFileA)(int, int, int, _DWORD, int, int, _DWORD); // eax
int v2; // ebx
int v3; // edi
unsigned int v5; // ecx
int v6; // edi
int v7; // eax
int v8; // [esp-4h] [ebp-3Ch]
char v9[36]; // [esp+Ch] [ebp-2Ch] BYREF
int v10; // [esp+30h] [ebp-8h]
int v11; // [esp+34h] [ebp-4h] BYREF
memset(v9, 0, sizeof(v9));
CreateFileA = *(int (__stdcall **)(int, int, int, _DWORD, int, int, _DWORD))a1;
v2 = a1 + 20;
v11 = 0;
v3 = CreateFileA(a1 + 20, -1073741824, 1, 0, 3, 128, 0);
v10 = v3;
if ( v3 != -1 )
{
if ( !(*(int (__stdcall **)(int, char *, int, int *, _DWORD))(a1 + 4))(v3, v9, 32, &v11, 0) )
{
v8 = v3;
LABEL_4:
(*(void (__stdcall **)(int))(a1 + 12))(v8);
return 0;
}
v5 = 0;
if ( &v9[strlen(v9) + 1] != &v9[1] )
{
do
v9[v5++] ^= 9u;
while ( v5 < strlen(v9) );
v3 = v10;
}
(*(void (__stdcall **)(int))(a1 + 12))(v3);
(*(void (__stdcall **)(int))(a1 + 16))(v2);
v6 = (*(int (__stdcall **)(int, int, int, _DWORD, int, int, _DWORD))a1)(v2, -1073741824, 1, 0, 2, 128, 0);
v7 = (*(int (__stdcall **)(int, char *, unsigned int, int *, _DWORD))(a1 + 8))(v6, v9, strlen(v9), &v11, 0);
v8 = v6;
if ( !v7 )
goto LABEL_4;
(*(void (__stdcall **)(int))(a1 + 12))(v6);
}
return 0;
}
由于转储没修复好,因此无法读取到资源
因此将Reme.exe拖入xdbg中分析,对sizeofresource下硬件执行断点
读取资源
该资源大小为b800
对提取出的资源进行异或解密
解密出一个pe文件
创建进程,其中ebx所在的地址的第三个值即使进程的pid
分配内存
循环写入内存,修复释放的pe文件
使用xdbg附加到创建的进程,并转储刚刚注入的文件
拖入die
拖入ida中,发现了一个有趣的东西
主函数为,其中输入的参数是'D:\test'
判断文件类型是否为文件夹,如果是文件夹,就递归进入该函数
if ( (FindFileData.dwFileAttributes & 0x10) != 0 )
{
if ( FindFileData.cFileName[0] != 46 )
{
wsprintfA(FileName, "%s\\%s", lpString2, FindFileData.cFileName);
sub_F21000(FileName);
}
如果是文件,就判断后缀是否等于以下几个
如果判断成功,就进入下一个函数,读取文件,并进行加密
HANDLE __thiscall sub_F21230(LPCSTR lpFileName)
{
_BYTE *v2; // eax
char v4; // cl
HANDLE result; // eax
void *v6; // esi
void *v7; // edi
DWORD NumberOfBytesRead; // [esp+8h] [ebp-210h] BYREF
_BYTE Buffer[260]; // [esp+Ch] [ebp-20Ch] BYREF
CHAR FileName[260]; // [esp+110h] [ebp-108h] BYREF
memset(Buffer, 0, sizeof(Buffer));
memset(FileName, 0, sizeof(FileName));
NumberOfBytesRead = 0;
strcpy(FileName, lpFileName);
v2 = &Buffer[259];
while ( *++v2 )
;
v4 = byte_F2ACEC;
*(_DWORD *)v2 = dword_F2ACE8;
v2[4] = v4;
result = CreateFileA(lpFileName, 0xC0000000, 1u, 0, 3u, 0x80u, 0);
v6 = result;
if ( result != (HANDLE)-1 )
{
result = CreateFileA(FileName, 0xC0000000, 1u, 0, 2u, 0x80u, 0);
v7 = result;
if ( result != (HANDLE)-1 )
{
ReadFile(v6, Buffer, 0x104u, &NumberOfBytesRead, 0);
sub_F21360(Buffer);
WriteFile(v7, Buffer, 0x20u, &NumberOfBytesRead, 0);
CloseHandle(v7);
return (HANDLE)CloseHandle(v6);
}
}
return result;
}
加密函数为,进入其中子函数观察
int __thiscall sub_F21360(char *this)
{
_BYTE v3[508]; // [esp+4h] [ebp-210h] BYREF
_DWORD v4[4]; // [esp+200h] [ebp-14h] BYREF
v4[0] = 370507323;
v4[1] = -1496142280;
v4[2] = -2011826245;
v4[3] = 1011863321;
memset(v3, 0, sizeof(v3));
sub_F21450(v3, 0, 16, v4, 0);
sub_F21930(v3, this);
return sub_F21930(v3, this + 16);
}
明显是aes加密
其中密钥为
v4[0] = 0x16157E3B;
v4[1] = 0xA6D2AE38;
v4[2] = 0x8815F7BB;
v4[3] = 0x3C4FCF19;
使用python解密
from Crypto.Cipher import AES
keys=bytes([0x3b,0x7e,0x15,0x16,0x38,0xae,0xd2,0xa6,0xbb,0xf7,0x15,0x88,0x19,0xcf,0x4f,0x3c])
data = open('./flag.txt.cry','rb').read()
aes = AES.new(keys, AES.MODE_ECB)
honduras = aes.decrypt(data)
decrypted_data=[]
for i in honduras:
decrypted_data.append(i^9)
print(bytes(decrypted_data))
得到结果
b'wdflag{70O9TSGICPQSLGDC}\t\t\t\t\t\t\t\t'
该文章对名为 ReMe.exe
的勒索加密程序进行了深入分析,包括其基础信息、加密算法(AES-ECB)和执行流程。通过逆向工程,揭示了该程序的自解密、进程注入及加密机制,并最终利用 Python 成功解密出题目要求的 flag
值。
3 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!