Position
进入sub_401740(this)
int __stdcall sub_401740(int a1)
{
int v1; // edi
int v3; // esi
int v4; // esi
__int16 v5; // bx
char v6; // al
char v7; // al
unsigned __int8 v8; // bl
wchar_t *v9; // eax
__int16 v10; // di
wchar_t *v11; // eax
__int16 v12; // di
wchar_t *v13; // eax
__int16 v14; // di
wchar_t *v15; // eax
__int16 v16; // di
wchar_t *v17; // eax
__int16 v18; // di
char v19; // al
char v20; // al
unsigned __int8 v21; // bl
wchar_t *v22; // eax
__int16 v23; // di
wchar_t *v24; // eax
__int16 v25; // di
wchar_t *v26; // eax
__int16 v27; // di
wchar_t *v28; // eax
__int16 v29; // di
wchar_t *v30; // eax
__int16 v31; // si
unsigned __int8 v32; // [esp+10h] [ebp-28h]
unsigned __int8 v33; // [esp+10h] [ebp-28h]
unsigned __int8 v34; // [esp+11h] [ebp-27h]
unsigned __int8 v35; // [esp+11h] [ebp-27h]
unsigned __int8 v36; // [esp+13h] [ebp-25h]
unsigned __int8 v37; // [esp+13h] [ebp-25h]
unsigned __int8 v38; // [esp+14h] [ebp-24h]
unsigned __int8 v39; // [esp+14h] [ebp-24h]
unsigned __int8 v40; // [esp+18h] [ebp-20h]
unsigned __int8 v41; // [esp+18h] [ebp-20h]
unsigned __int8 v42; // [esp+19h] [ebp-1Fh]
unsigned __int8 v43; // [esp+19h] [ebp-1Fh]
unsigned __int8 v44; // [esp+1Ah] [ebp-1Eh]
unsigned __int8 v45; // [esp+1Ah] [ebp-1Eh]
unsigned __int8 v46; // [esp+1Bh] [ebp-1Dh]
unsigned __int8 v47; // [esp+1Bh] [ebp-1Dh]
unsigned __int8 v48; // [esp+1Ch] [ebp-1Ch]
unsigned __int8 v49; // [esp+1Ch] [ebp-1Ch]
int v50; // [esp+20h] [ebp-18h] BYREF
int v51; // [esp+24h] [ebp-14h] BYREF
char v52[4]; // [esp+28h] [ebp-10h] BYREF
int v53; // [esp+34h] [ebp-4h]
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v50);
v1 = 0;
v53 = 0;
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v51);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(v52);
LOBYTE(v53) = 2;
CWnd::GetWindowTextW(a1 + 304, &v50);
if ( *(_DWORD *)(v50 - 12) == 4 )
{
v3 = 0;
while ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v3) >= 0x61u
&& (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v3) <= 0x7Au )
{
if ( ++v3 >= 4 )
{
LABEL_7:
v4 = 0;
while ( 1 )
{
if ( v1 != v4 )
{
v5 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v4);
if ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, v1) == v5 )
goto LABEL_2;
}
if ( ++v4 >= 4 )
{
if ( ++v1 < 4 )
goto LABEL_7;
CWnd::GetWindowTextW(a1 + 420, &v51);
if ( *(_DWORD *)(v51 - 12) == 11 && (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 5) == 45 )
{
v6 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 0);
v40 = (v6 & 1) + 5;
v48 = ((v6 & 0x10) != 0) + 5;
v42 = ((v6 & 2) != 0) + 5;
v44 = ((v6 & 4) != 0) + 5;
v46 = ((v6 & 8) != 0) + 5;
v7 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 1);
v32 = (v7 & 1) + 1;
v38 = ((v7 & 0x10) != 0) + 1;
v34 = ((v7 & 2) != 0) + 1;
v8 = ((v7 & 4) != 0) + 1;
v36 = ((v7 & 8) != 0) + 1;
v9 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v40 + v8, v9, 0xAu, 10);
v10 = ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0);
if ( (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 0) == v10 )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v11 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v46 + v36, v11, 0xAu, 10);
v12 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 1);
if ( v12 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v13 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v42 + v38, v13, 0xAu, 10);
v14 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 2);
if ( v14 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v15 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v44 + v32, v15, 0xAu, 10);
v16 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 3);
if ( v16 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v17 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v48 + v34, v17, 0xAu, 10);
v18 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 4);
if ( v18 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v19 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 2);
v41 = (v19 & 1) + 5;
v49 = ((v19 & 0x10) != 0) + 5;
v43 = ((v19 & 2) != 0) + 5;
v45 = ((v19 & 4) != 0) + 5;
v47 = ((v19 & 8) != 0) + 5;
v20 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v50, 3);
v33 = (v20 & 1) + 1;
v39 = ((v20 & 0x10) != 0) + 1;
v35 = ((v20 & 2) != 0) + 1;
v21 = ((v20 & 4) != 0) + 1;
v37 = ((v20 & 8) != 0) + 1;
v22 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v41 + v21, v22, 0xAu, 10);
v23 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 6);
if ( v23 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v24 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v47 + v37, v24, 0xAu, 10);
v25 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 7);
if ( v25 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v26 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v43 + v39, v26, 0xAu, 10);
v27 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 8);
if ( v27 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v28 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v45 + v33, v28, 0xAu, 10);
v29 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 9);
if ( v29 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
v30 = (wchar_t *)ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v52);
itow_s(v49 + v35, v30, 0xAu, 10);
v31 = ATL::CSimpleStringT<wchar_t,1>::GetAt(&v51, 10);
if ( v31 == (unsigned __int16)ATL::CSimpleStringT<wchar_t,1>::GetAt(v52, 0) )
{
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v52, -1);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(v52);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v51);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v50);
return 1;
}
}
}
}
}
}
}
}
}
}
}
goto LABEL_2;
}
}
}
}
}
LABEL_2:
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(v52);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v51);
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v50);
return 0;
}
C++的API很长, 其实把出现的所有API汇总一下, 就是下面这些
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(&v);
// 从GUI窗口拿input
CWnd::GetWindowTextW(a, &v);
ATL::CSimpleStringT<wchar_t,1>::GetAt(&v, cnt); // 相当于取数组v[cnt]
ATL::CSimpleStringT<wchar_t,1>::GetBuffer(v); // 相当于去数组v
ATL::CSimpleStringT<wchar_t,1>::ReleaseBuffer(v, -1); // 相当于free(v)
itow_s(v41 + v21, v22, 0xAu, 10); // 相当于 v41 + v21的整数转换生成 string 存储到 v22
ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::~CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(v); // 和第一行差别只在 ~ 应该是析构函数
简化一下代码就得到
// 前两位
v6 = Name[0]
v7 = (v6 & 1) + 5
v48 = ((v6 >> 4) & 1) + 5
v42 = ((v6 >> 1) & 1) + 5
v44 = ((v6 >> 2) & 1) + 5
v46 = ((v6 >> 3) & 1) + 5
v8 = Name[1]
v34 = (v8 & 1) + 1
v40 = ((v8 >> 4) & 1) + 1
v36 = ((v8 >> 1) & 1) + 1
v9 = ((v8 >> 2) & 1) + 1
v38 = ((v8 >> 3) & 1) + 1
v7 + v9 = Serial[0]
v46 + v38 = Serial[1]
v42 + v40 = Serial[2]
v44 + v34 = Serial[3]
v48 + v36 = Serial[4]
// 后两位
v20 = Name[2]
v21 = (v20 & 1) + 5
v49 = ((v20 >> 4) & 1) + 5
v43 = ((v20 >> 1) & 1) + 5
v45 = ((v20 >> 2) & 1) + 5
v47 = ((v20 >> 3) & 1) + 5
v22 = Name[3]
v35 = (v22 & 1) + 1
v41 = ((v22 >> 4) & 1) + 1
v37 = ((v22 >> 1) & 1) + 1
v23 = ((v22 >> 2) & 1) + 1
v39 = ((v22 >> 3) & 1) + 1
v21 + v23 = Serial[6]
v47 + v39 = Serial[7]
v43 + v41 = Serial[8]
v45 + v35 = Serial[9]
v49 + v37 = Serial[10]
不定方程, 直接爆破
# 先爆破 Name 前两位
Serial='76876_77776'
for i in range(ord('a'),ord('z')+1):
for j in range(ord('a'),ord('z')+1):
v6=i
v8=j
v7 = (v6 & 1) + 5
v48 = ((v6 >> 4) & 1) + 5
v42 = ((v6 >> 1) & 1) + 5
v44 = ((v6 >> 2) & 1) + 5
v46 = ((v6 >> 3) & 1) + 5
v34 = (v8 & 1) + 1
v40 = ((v8 >> 4) & 1) + 1
v36 = ((v8 >> 1) & 1) + 1
v9 = ((v8 >> 2) & 1) + 1
v38 = ((v8 >> 3) & 1) + 1
if v7 + v9 == int(Serial[0]) and v46 + v38 == int(Serial[1]) and v42 + v40 == int(Serial[2]) and v44 + v34 == int(Serial[3]) and v48 + v36 == int(Serial[4]):
print(chr(i),chr(j))
print()
# 再爆破后两位
for i in range(ord('a'),ord('z')+1):
for j in range(ord('a'),ord('z')+1):
v20=i
v22=j
v21 = (v20 & 1) + 5
v49 = ((v20 >> 4) & 1) + 5
v43 = ((v20 >> 1) & 1) + 5
v45 = ((v20 >> 2) & 1) + 5
v47 = ((v20 >> 3) & 1) + 5
v35 = (v22 & 1) + 1
v41 = ((v22 >> 4) & 1) + 1
v37 = ((v22 >> 1) & 1) + 1
v23 = ((v22 >> 2) & 1) + 1
v39 = ((v22 >> 3) & 1) + 1
if v21 + v23 == int(Serial[6]) and v47 + v39 == int(Serial[7]) and v43 + v41 == int(Serial[8]) and v45 + v35 == int(Serial[9]) and v49 + v37 == int(Serial[10]):
print(chr(i),chr(j))
后两位只有mp满足提示, 依次尝试前两位的4种情况.
bump
cqmp
ftmp
gpmp
只有最后一个是错误的
bump
cqmp
ftmp
Direct3D FPS
FPS游戏, 不懂要干嘛, 随意玩玩发现碰到保龄球就输了
IDA搜string
应该就是游戏结束的提示语句, 回溯到判断函数
int *sub_4039C0()
{
int *result; // eax
result = &dword_409194;
while ( *result != 1 )
{
result += 132;
if ( (int)result >= (int)&unk_40F8B4 )
{
MessageBoxA(hWnd, aCkfkbulileEZf, "Game Clear!", 0x40u);
return (int *)SendMessageA(hWnd, 2u, 0, 0);
}
}
return result;
}
dowrd_409194是关键, 回溯到关键函数
int __thiscall sub_403400(void *this)
{
int result; // eax
int v2; // edx
result = sub_403440(this);
if ( result != -1 )
{
v2 = dword_409190[132 * result];
if ( v2 > 0 )
{
dword_409190[132 * result] = v2 - 2;
}
else
{
dword_409194[132 * result] = 0;
aCkfkbulileEZf[result] ^= byte_409184[528 * result];
}
}
return result;
}
int sub_403440()
{
int v0; // edi
int v1; // ebx
_DWORD *v2; // esi
int *v3; // esi
int v5; // [esp+8h] [ebp-Ch]
float v6; // [esp+Ch] [ebp-8h]
float v7; // [esp+10h] [ebp-4h] BYREF
v6 = 999999.0;
v0 = 0;
v5 = 0;
v1 = 0;
v2 = &unk_408F90;
do
{
if ( v2[129] && sub_4027C0(v2, &v7) && v6 > (double)v7 )
{
v6 = v7;
v5 = v0;
v1 = 1;
}
v2 += 132;
++v0;
}
while ( (int)v2 < (int)&flt_40F6B0 );
if ( v1 && (!sub_4027C0(&dword_407260, &v7) || v6 <= (double)v7) )
{
v3 = &dword_407D90;
while ( !sub_4027C0(v3, &v7) || v6 <= (double)v7 )
{
v3 += 128;
if ( (int)v3 >= (int)&unk_408F90 )
return v5;
}
}
return -1;
}
aCkfkbulileEZf这东西很奇怪, 回顾Game clear那个函数
判断这玩意儿就是flag. 所以sub_403400
是计算flag的函数. 查看byte_409184, 发现值不确定, 接着动态调试查看相应数组数值
s = [0x43, 0x6B, 0x66, 0x6B, 0x62, 0x75, 0x6C, 0x69, 0x4C, 0x45,
0x5C, 0x45, 0x5F, 0x5A, 0x46, 0x1C, 0x07, 0x25, 0x25, 0x29,
0x70, 0x17, 0x34, 0x39, 0x01, 0x16, 0x49, 0x4C, 0x20, 0x15,
0x0B, 0x0F, 0xF7, 0xEB, 0xFA, 0xE8, 0xB0, 0xFD, 0xEB, 0xBC,
0xF4, 0xCC, 0xDA, 0x9F, 0xF5, 0xF0, 0xE8, 0xCE, 0xF0, 0xA9]
flag = ''
for i in range(len(s)):
flag+=chr(s[i] ^ (i*4))
print(flag)
Thr3EDPr0m
Ransomware
一个加入了垃圾代码的勒索病毒
upx脱壳, 直接F5出错, 发现有花指令, 所以出题者在函数入口加了很多花指令让IDA无法反编译
IDC patch掉
auto i, starts = 0x00401000, ends = 0x0044A775;
for(i = starts; i < ends; i++)
PatchByte(i,0x90);
Message("\n" + "OK\n");
然后手动把函数入口的二进制码55 8B EC 83 EC 24 53 56 57
修改到有效指令开头
设定main函数起始和结束地址
再F5反编译, 这下伪代码就很好看了, sub_401000
是patch掉的花指令, 可以忽略
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // kr00_4
FILE *v5; // [esp+1Ch] [ebp-14h]
unsigned int v6; // [esp+20h] [ebp-10h]
int v7; // [esp+28h] [ebp-8h]
unsigned int i; // [esp+28h] [ebp-8h]
unsigned int j; // [esp+28h] [ebp-8h]
FILE *Stream; // [esp+2Ch] [ebp-4h]
printf("Key : ");
sub_401000();
scanf("%s", byte_44D370);
v3 = strlen(byte_44D370);
sub_401000();
v7 = 0;
Stream = fopen("file", "rb");
sub_401000();
if ( !Stream )
{
sub_401000();
printf(byte_44C1C4);
sub_401000();
exit(0);
}
fseek(Stream, 0, 2);
sub_401000();
v6 = ftell(Stream);
sub_401000();
rewind(Stream);
sub_401000();
while ( !feof(Stream) )
{
sub_401000();
byte_5415B8[v7] = fgetc(Stream);
sub_401000();
++v7;
sub_401000();
}
sub_401000();
for ( i = 0; i < v6; ++i )
{
byte_5415B8[i] ^= byte_44D370[i % v3];
sub_401000();
byte_5415B8[i] = ~byte_5415B8[i];
sub_401000();
}
fclose(Stream);
sub_401000();
v5 = fopen("file", "wb");
sub_401000();
sub_401000();
for ( j = 0; j < v6; ++j )
{
fputc(byte_5415B8[j], v5);
sub_401000();
}
printf(byte_44C1E8);
sub_401000();
return getch();
}
分析得知就是一个简单xor和取反加密, 找到key就可以直接解密文件了
利用正常exe的二进制信息
有一段This program cannot be run in DOS mode
是固定的二进制信息, 再用加密后的二进制文件file
对应位置串与之xor即可求得key
file = open('file', 'rb')
byte_array = bytearray(file.read(0x74))
byte_array_ori = b'This program cannot be run in DOS mode'
file.close()
key = ''
for i in range(0x4E, 0x74):
key += chr((byte_array[i] ^ byte_array_ori[i - 0x4E]) ^ 0xFF)
print(key)
所以key是letsplaychess
输入, 解密
解密得到一个exe(手动修改后缀), 运行得到flag