PETools查看概况
32位程序, Section: [.text], EP: 0x00000400,无壳。
被逆向exe可在资源下载1下载。
作者:hans774882968以及hans774882968
IDA静态分析
打开IDA,我们很快找到了唯一需要关注的函数。
INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
HICON v4; // eax@2
unsigned int v5; // et0@2
int v6; // esi@2
unsigned __int8 v7; // al@3
__int16 v9; // ax@8
HANDLE v10; // eax@13
DWORD v11; // eax@14
HGLOBAL v12; // eax@16
HANDLE v13; // eax@25
unsigned int v14; // et0@26
int v15; // ecx@26
unsigned int v16; // [sp-24h] [bp-24h]@2
unsigned int v17; // [sp-24h] [bp-24h]@26
if ( a2 != 272 )
{
if ( a2 == 16 )
EndDialog(hWnd, 0);
if ( a2 != 273 )
return 0;
v9 = a3;
if ( (_WORD)a3 == 104 )
v9 = EndDialog(hWnd, 0);
if ( v9 == 105 )
v9 = MessageBoxA(0, Text, Caption, 0x40u);
if ( v9 != 106 )
{
LABEL_24:
if ( v9 == 103 )
{
OpenClipboard(0);
v13 = GetClipboardData(1u);
if ( !v13 )
goto LABEL_35;
dword_403233 = (int)v13;
v14 = __readeflags();
v17 = v14;
dword_403342 = dword_40333E;
v15 = dword_403346;
do
dword_403342 -= *((char *)v13 + v15-- - 1);
while ( v15 );
__writeeflags(v17);
if ( 0 == dword_403342 )
{
SetDlgItemTextA(hWnd, 102, aStep1OkNowRegi);
EnableWindow(dword_403356, 0);
EnableWindow(::hWnd, 1);
}
else
{
LABEL_35:
SetDlgItemTextA(hWnd, 102, aRegistrationFa);
}
CloseClipboard();
}
return 0;
}
v10 = CreateFileA(FileName, 0x80000000, 1u, 0, 3u, 0x80u, 0);
if ( v10 == (HANDLE)-1 )
goto LABEL_22;
hFile = v10;
v11 = GetFileSize(v10, 0);
if ( v11 < 8 )
{
CloseHandle(hFile);
LABEL_22:
SetDlgItemTextA(hWnd, 102, aRegistrationFa);
EnableWindow(::hWnd, 0);
EnableWindow(dword_403356, 1);
goto LABEL_23;
}
nNumberOfBytesToRead = v11;
v12 = GlobalAlloc(0x40u, v11);
if ( v12 )
{
lpBuffer = v12;
if ( !ReadFile(hFile, v12, nNumberOfBytesToRead, &NumberOfBytesRead, 0) )
{
CloseHandle(hFile);
GlobalFree(lpBuffer);
goto LABEL_22;
}
CloseHandle(hFile);
if ( dword_403342 + (*((_DWORD *)lpBuffer + 1) ^ *(_DWORD *)lpBuffer) != dword_40333E )
goto LABEL_22;
SetDlgItemTextA(hWnd, 102, aGoodWork_YouHa);
EnableWindow(::hWnd, 0);
}
else
{
SetDlgItemTextA(hWnd, 102, aMemoryAllocati);
CloseHandle(hFile);
}
LABEL_23:
v9 = (unsigned int)GlobalFree(lpBuffer);
goto LABEL_24;
}
v4 = LoadIconA(hInstance, (LPCSTR)0x3E8);
SendMessageA(hWnd, 0x80u, 1u, (LPARAM)v4);
dword_403356 = GetDlgItem(hWnd, 103);
::hWnd = GetDlgItem(hWnd, 106);
nSize = 255;
GetComputerNameA(String, &nSize);
dword_403346 = lstrlenA(String);
v5 = __readeflags();
v16 = v5;
v6 = (int)String;
dword_40333E = 0;
do
{
v7 = *(_BYTE *)v6++;
dword_40333E += v7;
}
while ( v7 );
__writeeflags(v16);
return 0;
}
另外,查看字符串
aStep1OkNowRegi db 'Step 1 ok -> now Register it!',0
aGoodWork_YouHa db 'Good work. You have done it!',0
aRegistrationFa db 'Registration failed!!!',0
aMemoryAllocati db 'Memory allocation error!',0
FileName db 'reg.key',0
根据aStep1OkNowRegi。显然关键跳不止一处。
第一关
相关代码:
OpenClipboard(0);
v13 = GetClipboardData(1u);
if ( !v13 )
goto LABEL_35;
dword_403233 = (int)v13;
v14 = __readeflags();
v17 = v14;
dword_403342 = dword_40333E;
v15 = dword_403346;
do
dword_403342 -= *((char *)v13 + v15-- - 1);
while ( v15 );
__writeeflags(v17);
if ( 0 == dword_403342 )
{
SetDlgItemTextA(hWnd, 102, aStep1OkNowRegi);
EnableWindow(dword_403356, 0);
EnableWindow(::hWnd, 1);
}
else
{
LABEL_35:
SetDlgItemTextA(hWnd, 102, aRegistrationFa);
}
这段代码要求你剪贴板字符串ASCII值之和等于dword_403342。dword_403342初值来自于dword_40333E。那dword_40333E从哪来?狡猾啊!在DialogFunc最下面!
GetComputerNameA(String, &nSize);
dword_403346 = lstrlenA(String);
v5 = __readeflags();
v16 = v5;
v6 = (int)String;
dword_40333E = 0;
do
{
v7 = *(_BYTE *)v6++;
dword_40333E += v7;
}
while ( v7 );
__writeeflags(v16);
逻辑很简单,取出ComputerName,把每个字符的ASCII值加起来。因此一个合法方案就是复制ComputerName。
第二关
v10 = CreateFileA(FileName, 0x80000000, 1u, 0, 3u, 0x80u, 0);// reg.key
if ( v10 == (HANDLE)-1 )
goto LABEL_22;
hFile = v10;
v11 = GetFileSize(v10, 0);
if ( v11 < 8 )
{
CloseHandle(hFile);
LABEL_22:
SetDlgItemTextA(hWnd, 102, aRegistrationFa);
EnableWindow(::hWnd, 0);
EnableWindow(dword_403356, 1);
goto LABEL_23;
}
nNumberOfBytesToRead = v11;
v12 = GlobalAlloc(0x40u, v11);
if ( v12 )
{
lpBuffer = v12;
if ( !ReadFile(hFile, v12, nNumberOfBytesToRead, &NumberOfBytesRead, 0) )
{
CloseHandle(hFile);
GlobalFree(lpBuffer);
goto LABEL_22;
}
CloseHandle(hFile);
if ( dword_403342 + (*((_DWORD *)lpBuffer + 1) ^ *(_DWORD *)lpBuffer) != dword_40333E )
goto LABEL_22;
SetDlgItemTextA(hWnd, 102, aGoodWork_YouHa);
EnableWindow(::hWnd, 0);
}
else
{
SetDlgItemTextA(hWnd, 102, aMemoryAllocati);
CloseHandle(hFile);
}
因为不熟悉Windows api,在这个lpBuffer这里浪费了不少时间。根据 HGLOBAL v12; // eax@16和lpBuffer = v12或者强转为DWORD,可知lpBuffer是4字节的。那么*lpBuffer + 1实际上是取输入文件reg.key的第4~7字节(0-indexed)。另外查了下,GlobalAlloc(0x40u, v11)用来分配一段堆上的内存,大小为文件size(v11)。
dword_403342在上面减为0之后没有改变,因此总是0。所以这里需要我们构造一个reg.key文件,它的第0~3、4~7个字节作为整数x和y,满足x ^ y = dword_40333E。根据异或的性质可以秒掉。
如果想patch的话,就用IDA的patch功能把两个关键跳的汇编代码替换或者nop掉即可,难度比找到算法小。
注册机
下面的python3代码用到:
- bytearray可以直接写入文件
- bytearray的每个元素可以直接当int使
import os
computerName = os.environ['COMPUTERNAME']
ans = 0
for c in computerName:
ans += ord(c)
print(computerName,hex(ans))# 0x3fd
u = bytearray("hans",encoding = "utf-8")
v = bytearray([u[i] ^ (ans >> (8*i) & 0xff) for i in range(4)])
print(v)
with open("reg.key","wb") as f:
f.write(u)
f.write(v)
资源下载
- exe文件可以在这个视频的简介给出的链接找到。