经提醒想起有这么个东西,当时在忙着别的事。。。复现真是大开眼界,最大的收获就是知道了好多新名词
Re
d3w0w
int __cdecl main(int argc, const char **argv, const char **envp)
{
_DWORD v4[11]; // [esp+0h] [ebp-30h] BYREF
BOOL v5; // [esp+2Ch] [ebp-4h]
dword_4262F0 = (int)NtCurrentTeb()->WOW32Reserved;
memset(v4, 0, 0x27u);
sub_402100("%39s", (const char *)v4);
v5 = sub_401000(v4, &unk_4262F8) || sub_401220(&unk_4262F8, v4[0]);
v4[10] = v5;
if ( v5 )
sub_402090("you lose\n", v4[0]);
else
sub_402090("you win\n", v4[0]);
return 0;
}
经观察只需逆向sub_401000(v4, &unk_4262F8)
和 sub_401220(&unk_4262F8, v4[0])
即可,然后
int __cdecl sub_401000(_BYTE *a1, _DWORD *a2)
{
int v3; // [esp+0h] [ebp-10h]
int v4; // [esp+8h] [ebp-8h]
int v5; // [esp+Ch] [ebp-4h]
v5 = 0;
v4 = 0;
v3 = 6;
if ( *(_DWORD *)a1 != 'tc3d' )
return 1;
if ( *((_WORD *)a1 + 2) != '{f' )
return 1;
if ( a1[6] != '2' )
return 1;
while ( a1[v3] != '}' )
{
switch ( a1[v3] )
{
case '1': // 上移
a2[6 * v5 + v4] |= 8u;
a2[6 * --v5 + v4] |= 2u;
goto LABEL_14;
case '2': // 下移
a2[6 * v5 + v4] |= 2u;
a2[6 * ++v5 + v4] |= 8u;
goto LABEL_14;
case '3': // 左移
a2[6 * v5 + v4] |= 4u;
a2[6 * v5 - 1 + v4--] |= 1u;
goto LABEL_14;
case '4': // 右移
a2[6 * v5 + v4] |= 1u;
a2[6 * v5 + 1 + v4++] |= 4u;
LABEL_14:
if ( v5 < 0 || v4 < 0 || v5 > 5 || v4 > 5 )
return 1;
++v3;
break;
default:
return 1;
}
}
return 0;
}
flag的形式应该为d3ctf{[1-4]*},推测又是走迷宫,1-4对应四个方向,flag的长度为39
sub_401220
是WOW64混淆,天堂之门。动调。
动调出了然后卡死了,看emtanling大佬写的wp,当时也想到用64位执行,但pe结构是32位应该改pe结构的。。。
修改128h的magic,这个无符号整数指出了镜像文件的状态。
0x10B表明这是一个32位镜像文件。0x107表明这是一个ROM镜像。0x20B表明这是一个64位镜像文件。所以修改为0x20B
然后就能看到主要逻辑了
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall ________u_3___V_F__102(__int64 a1, __int64 a2)
{
_DWORD *v2; // rcx
__int64 v3; // rcx
int v5; // [rsp-10h] [rbp-B0h]
int v6; // [rsp-10h] [rbp-B0h]
int v7; // [rsp-10h] [rbp-B0h]
int v8; // [rsp-Ch] [rbp-ACh]
int v9; // [rsp-Ch] [rbp-ACh]
int v10; // [rsp-Ch] [rbp-ACh]
int i; // [rsp-8h] [rbp-A8h]
int j; // [rsp-4h] [rbp-A4h]
int v13; // [rsp+0h] [rbp-A0h]
int v14; // [rsp+4h] [rbp-9Ch]
int k; // [rsp+8h] [rbp-98h]
int m; // [rsp+Ch] [rbp-94h]
unsigned int v17; // [rsp+10h] [rbp-90h]
unsigned int v18; // [rsp+14h] [rbp-8Ch]
unsigned int v19; // [rsp+18h] [rbp-88h]
unsigned int v20; // [rsp+1Ch] [rbp-84h]
unsigned int v21; // [rsp+20h] [rbp-80h]
unsigned int v22; // [rsp+24h] [rbp-7Ch]
int v23[3]; // [rsp+28h] [rbp-78h]
int v24[10]; // [rsp+38h] [rbp-68h]
__int64 v25; // [rsp+60h] [rbp-40h]
__int64 v26; // [rsp+68h] [rbp-38h]
__int64 v27; // [rsp+70h] [rbp-30h]
__int64 v28; // [rsp+78h] [rbp-28h]
__int64 v29; // [rsp+80h] [rbp-20h]
__int64 v30; // [rsp+88h] [rbp-18h]
__int64 v31; // [rsp+98h] [rbp-8h]
_DWORD *savedregs; // [rsp+A0h] [rbp+0h]
((void (__fastcall *)(_QWORD, __int64))sub_34000000020510)((unsigned int)v31, a2);
savedregs = v2;
v23[0] = 0;
v23[1] = 14;
v23[2] = 20;
v24[0] = 4;
v24[1] = 13;
v24[2] = 15;
v24[3] = 21;
v24[4] = 24;
v24[5] = 31;
v24[6] = 32;
v24[7] = 41;
v24[8] = 45;
v24[9] = 53;
for ( i = 0; i < 6; ++i )
{
for ( j = 0; j < 6; ++j ) // 6*6方阵
{
v3 = j;
if ( savedregs[6 * i + j] > 15u ) // 不能大于15
return sub_34000000020521(v3);
v17 = savedregs[6 * i + j] % 0x10u / 8;
v25 = j;
v18 = savedregs[6 * i + j] % 8u / 4 + v17;
v26 = j;
v19 = savedregs[6 * i + j] % 4u / 2 + v18;
v27 = j;
v3 = savedregs[6 * i + j] % 2u + v19;
if ( savedregs[6 * i + j] % 2u + v19 > 2 )
return sub_34000000020521(v3);
if ( !j )
{
v3 = 4i64;
if ( savedregs[6 * i] % 8u / 4 ) // 不能为4的倍数
return sub_34000000020521(v3);
}
if ( j == 5 )
{
v3 = 2i64;
if ( savedregs[6 * i + 5] % 2u ) // 第6列值为2的倍数
return sub_34000000020521(v3);
}
if ( !i )
{
v3 = 8i64;
if ( savedregs[j] % 0x10u / 8 ) // 第1行数不能为8
return sub_34000000020521(v3);
}
if ( i == 5 )
{
v3 = 2i64;
if ( savedregs[j + 30] % 4u / 2 ) // 第6行的数不能为2
return sub_34000000020521(v3);
}
}
}
for ( k = 0; (unsigned __int64)k < 3; ++k )
{ // 黑子坐标
v5 = v23[k] / 10; // 0,1,2
v8 = v23[k] % 10; // 0,4,0
if ( savedregs[6 * v5 + v8] % 0x10u / 8 ) // 不能为8,2
{
v3 = 2i64;
if ( savedregs[6 * v5 + v8] % 4u / 2 )
return sub_34000000020521(v3);
}
if ( savedregs[6 * v5 + v8] % 8u / 4 ) // 不能为4,1
{
v3 = 2i64;
if ( savedregs[6 * v5 + v8] % 2u )
return sub_34000000020521(v3);
}
v20 = savedregs[6 * v5 + v8] % 0x10u / 8;
v28 = v8;
v21 = savedregs[6 * v5 + v8] % 4u / 2 + v20;
v29 = v8;
v22 = savedregs[6 * v5 + v8] % 2u + v21;
v30 = v8;
v3 = savedregs[6 * v5 + v8] % 8u / 4 + v22;
if ( savedregs[6 * v5 + v8] % 8u / 4 + v22 != 2 )
return sub_34000000020521(v3);
if ( savedregs[6 * v5 + v8] % 0x10u / 8 ) // 不为8, 猜测上一行不为8
return sub_3400000001F7F0(16i64, 0i64);
if ( savedregs[6 * v5 + v8] % 4u / 2 ) // 这个位置是2的话,下一行不是2
{
v3 = 2i64;
if ( !(savedregs[6 * v5 + 6 + v8] % 4u / 2) )
return sub_34000000020521(v3);
}
else if ( savedregs[6 * v5 + v8] % 8u / 4 ) // 这个位置为4上一个不为4
{
v3 = 4i64;
if ( !(savedregs[6 * v5 - 1 + v8] % 8u / 4) )
return sub_34000000020521(v3);
}
else if ( savedregs[6 * v5 + v8] % 2u ) // 当前为4下一个不为4
{
v3 = 2i64;
if ( !(savedregs[6 * v5 + 1 + v8] % 2u) )
return sub_34000000020521(v3);
}
}
for ( m = 0; (unsigned __int64)m < 0xA; ++m )
{ // 白字坐标
v6 = v24[m] / 10; // [0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
v9 = v24[m] % 10; // [4, 3, 5, 1, 4, 1, 2, 1, 5, 3]
if ( !(savedregs[6 * v6 + v9] % 0x10u / 8) || !(savedregs[6 * v6 + v9] % 4u / 2) )// 2和8
{
v3 = 4i64;
if ( !(savedregs[6 * v6 + v9] % 8u / 4) ) // 1和4
return sub_34000000020521(v3);
v3 = 2i64;
if ( !(savedregs[6 * v6 + v9] % 2u) ) // 不为1
return sub_34000000020521(v3);
}
if ( savedregs[6 * v6 + v9] % 0x10u / 8 )
{
if ( savedregs[6 * v6 + v9] % 4u / 2 ) // 2和8
{
if ( !(savedregs[6 * v6 - 6 + v9] % 8u / 4)// 上一行4或1或8
&& !(savedregs[6 * v6 - 6 + v9] % 2u)
&& !(savedregs[6 * v6 + 6 + v9] % 8u / 4) )
{
v3 = 2i64;
if ( !(savedregs[6 * v6 + 6 + v9] % 2u) )// 下一行4或1
return sub_34000000020521(v3);
}
}
}
if ( savedregs[6 * v6 + v9] % 8u / 4 )
{
if ( savedregs[6 * v6 + v9] % 2u ) // 1和4
{
if ( !(savedregs[6 * v6 + 1 + v9] % 0x10u / 8)// 右一行2或8
&& !(savedregs[6 * v6 + 1 + v9] % 4u / 2)
&& !(savedregs[6 * v6 - 1 + v9] % 0x10u / 8) )
{
v3 = 2i64;
if ( !(savedregs[6 * v6 - 1 + v9] % 4u / 2) )// 左一行2或8
return sub_34000000020521(v3);
}
}
}
}
v13 = 0;
v14 = 0;
v7 = 0;
v10 = 0;
if ( *savedregs % 0x10u / 8 )
{
v7 = -1;
while ( 1 )
{
LABEL_66:
v3 = 8i64;
if ( !(savedregs[6 * v7 + v10] % 0x10u / 8) || v7 - 1 == v13 && v10 == v14 )// 8,转向上一行
{
v3 = 2i64;
if ( !(savedregs[6 * v7 + v10] % 4u / 2) || v7 + 1 == v13 && v10 == v14 )// 2下转
{
v3 = 4i64;
if ( !(savedregs[6 * v7 + v10] % 8u / 4) || v7 == v13 && v10 - 1 == v14 )// 4左转
{
v3 = 2i64;
if ( !(savedregs[6 * v7 + v10] % 2u) || v7 == v13 && v10 + 1 == v14 )// 1右转
return sub_34000000020521(v3);
v13 = v7;
v14 = v10++;
}
else
{
v13 = v7;
v14 = v10--;
}
}
else
{
v13 = v7;
v14 = v10;
++v7;
}
}
else
{
v13 = v7;
v14 = v10;
--v7;
}
if ( !v7 && !v10 )
return sub_34000000020521(v3);
}
}
if ( *savedregs % 4u / 2 )
{
v7 = 1;
goto LABEL_66;
}
if ( *savedregs % 8u / 4 )
{
v10 = -1;
goto LABEL_66;
}
v3 = 2i64;
if ( *savedregs % 2u )
{
v10 = 1;
goto LABEL_66;
}
return sub_34000000020521(v3);
}
1对于向上的8,2对于向下的2,3对于向左的4,4对于向右的1
。(就是小键盘,除了向右)
然后就是puzzle,masyu,连成一闭合回路就好
d3ctf{22441442223133324424441111133333}
D3Re
UWP逆向,依赖装不上???win11已弃用???
等之后装好win10虚拟机试试吧。。。
d3hotel
u3d和wasm
本题由两部分组成,包括 luac 逆向以及 wasm 逆向。首先下载得到 BuildWebGL.wasm 和
BuildWebGL.data。
assetstudio解包得到global-metadata.dat
中断,之前分析的被我删了,没有文件了。。。
不过好像是个矩阵的密码题,我也做不出来。。。
看看翻车鱼大佬的吧
d3mug
看了半天才发现是unity3d,(怎么又是u3d)
教你使用IL2CppDumper从Unity il2cpp的二进制文件中获取类型、方法、字段等(反编译)
解压进入目录中,拿到libil2cpp.so与global-metadata.dat。
\lib\armeabi-v7a\libil2cpp.so
\assets\bin\Data\Managed\Metadata\global-metadata.dat
建立input和output文件夹,将上两个文件放入input,建立il2cpp_decompilation.bat 写入..\Il2CppDumper.exe libil2cpp.so global-metadata.dat ..\output
双击运行。得到
进入DummyDll,使用dnSpy分析Assembly-CSharp.dll,
关键函数GameManagerNoteHit (命中数)和 GameManagerNoteMissed (miss数)以及 ScoreScene__Start(得分数)
使用IDA逆向il2cpp.so,用script选择ida_with_struct_py3.py、script.json、il2cpp.h 加载自动分析,
通过IDA分析上述三个函数
打开stringliteral.json
逻辑没太看懂,就先这样吧
d3thon
首先运行main.py试试,报错
ImportError: byte_analizer.so: undefined symbol: Py_EnterRecursiveCall
Py_EnterRecursiveCall是python3.10.2的,所以安装python3.10.2
在用ipython运行
通过运行可知start函数输入flag
测试kuhisCvwaXWfqCs:flag
报错ValueError: invalid literal for int() with base 10:
即输入的是str型当运行okokok函数不在报错。
可知运行okokok函数是将str转换为int型
在okokokok函数中有四个类型的运算,分别是
IEKMEDdrPpzpdKy
OcKUQCYqhwHXfAgGZH
FLNPsiCIvICFtzpUAR
kuhisCvwaXWfqCs
下面分别对其进行测试:
开始flag为:12345678901324567890
首先运行kuhisCvwaXWfqCs:flag
结果为-12345678901234567891
,
经过测试结果为取反
s=12345678901234567890
print(~s)
# -12345678901234567891
测试IEKMEDdrPpzpdKy
加法运算
s=-12345678901234567891
n=10641779330030268582371809187351647903979911439280211955812317507748263879299639
res=10641779330030268582371809187351647903979911439280211955812305162069362644731748
print(res-n)
# res=s+n
测试OcKUQCYqhwHXfAgGZH
异或运算
s=10641779330030268582371809187351647903979911439280211955812305162069362644731748
n=12658175988133673916668965029924777191548654467512522015899145443664296208583935
res=6335108005929618188748493643939642720594287999173416915586700348266136222075803
print(res^n==s)
测试FLNPsiCIvICFtzpUAR
减法运算
s=6335108005929618188748493643939642720594287999173416915586700348266136222075803
n=28
res=6335108005929618188748493643939642720594287999173416915586700348266136222075775
print(res==s-n)
脚本
# IEKMEDdrPpzpdKy +
# OcKUQCYqhwHXfAgGZH ^
# FLNPsiCIvICFtzpUAR -
# kuhisCvwaXWfqCs ~
s = []
n = -194952731925593882593246917508862867371733438849523064153861650948471779982880938
with open('./1.txt', 'r') as f: # 将37行复制出来到1.txt逆向操作即可
s = f.read().split(",")
s.reverse()
for i in s:
r = i.split(":")
# print(r)
if "'IEKMEDdrPpzpdKy" == r[0]:
num = int(r[2].replace('\'', '')) # 尾部有个单引号
n -= num
elif "'FLNPsiCIvICFtzpUAR" == r[0]:
num = int(r[2].replace('\'', ''))
n += num
elif "'OcKUQCYqhwHXfAgGZH" == r[0]:
num = int(r[2].replace('\'', ''))
n ^= num
else:
n = ~n
print(bytes.fromhex(hex(n)[2:]))
b'4729a4a6bbdd4d78c94e6229257af35e'
d3arm
bin文件猜测是stm32的固件逆向
[原创]使用IDA pro逆向ARM M系核心的Bin固件
借此可以判断 ram 的基址为 0x20000000,代码段的基址为 0x8000000
SRecord 1.64 下载地址:http://srecord.sourceforge.net/download.html
试了一下用SRecord 将bin转为hex好像没什么用。。。
用ida反编译,架构选择 arm 小端,在 详细设置里面选择 ARMv7-M(但是不知道为什么,mbedOS搜了一下是arm7可能是这个原因?)。
进一步设置
然后按c+p,create function,搜索flag,跳转
dword_2000326C交叉引用,跳转sub_8005E20
发现主要逻辑
因为flag is shown below ,所以byte_200022C8为flag
int sub_8005E20()
{
if ( dword_20002304 != dword_200022F4 || dword_20002308 != dword_200022F8 )
return 0;
if ( dword_2000326C <= 41 )
byte_200022C8[dword_2000326C] = dword_800DB64[4 * dword_2000326C] ^ byte_20002314;
return 1;
}
// 可直接得到dword_800DB64
dword_800DB64=[0x20,0x6D,0x50,0x30,0x38,0x48,0x75,0x69,0x50,0x75,0x6B,0x56,0x20,0x6D,0x04,0x26,0x6A,0x51,0x72,0x6B,0x50,0x73,0x38,0x0B,0x74,0x6A,0x57,0x70,0x6E,0x50,0x25,0x3A,0x51,0x22,0x6E,0x56,0x75,0x3D,0x50,0x72,0x6A,0x4E]
然后获取byte_20002314
_DWORD *sub_8005DB0()
{
_DWORD *result; // r0
int v1; // r1
bool v2; // cc
int *v3; // r1
int *v4; // r2
result = (_DWORD *)sub_8007850(12);
v1 = ++dword_2000326C % 3;
v2 = (unsigned int)(dword_2000326C % 3) > 2;
*result = 0;
result[1] = 0;
result[2] = 0;
if ( !v2 )
byte_20002314 = 0x335E44u >> (8 * v1);
v3 = &dword_20002304;
do
{
v4 = v3;
v3 = (int *)v3[2];
}
while ( v3 );
v4[2] = (int)result;
return result;
}
// sub_8005850 部分
int sub_8005850()
{
_DWORD *v0; // r4
_DWORD *v1; // r0
dword_2000326C = 0;
byte_20002314 = 0x44;
推测byte_20002314=[0x44,0x5E,0x33];
脚本
s=[0x20,0x6D,0x50,0x30,0x38,0x48,0x75,0x69,0x50,0x75,0x6B,0x56,0x20,0x6D,0x04,0x26,0x6A,0x51,0x72,0x6B,0x50,0x73,0x38,0x0B,0x74,0x6A,0x57,0x70,0x6E,0x50,0x25,0x3A,0x51,0x22,0x6E,0x56,0x75,0x3D,0x50,0x72,0x6A,0x4E]
key=[0x44,0x5e,0x33]
for i in range(len(s)):
print(chr(s[i]^key[i%3]),end='')
# d3ctf{17c15ed37b4b65c7f804d40cadbf0e1cc64}
ghidra 对固件逆向要更为友好,之后看看拿ghidra分析一下