该题使用如下的混淆手法,阻碍反编译实施:
即将普通的相对转移流程改为使用push const+pop register+jmp register实现,只要手工还原即可还原代码,正常反编译:
sub_804865B、sub_804857B、sub_80485**分别为基于环境变量、ptrace等反调试
除此之外,处理流程是输入是一个十进制整数,然后对该整数+1、+1、+0xCCCCCCCC、+1,之后进入sub_8048753:
该函数把之前计算的整数作为地址,对该地址patch两个nop指令:
通过查看汇编代码,该处jmp指令导致流程永远指向wrong:
所以正确输入即0x8048765-1-0xCCCCCCCC-1-1=993507990
即:flag{993507990}
main调用主要check逻辑MainLogic2Check :
该函数为UnManaged Code,函数文件偏移 0x0019F920 :
首先调用Managed Code,检查flag的格式是否为111111-111111-111111-11111111111111(1代表任意):
sub_5A04D0将十六进制字符串转为十六进制:
接着check477函数回到Managed Code层:
Managed Code层又调用UnManaged Code层,文件偏移 0x000C6590 :
终于定位到了真正的check逻辑,在UnManaged Code中的0x4C7190处(下面同时给出跟踪流程)
int __cdecl check477(unsigned __int8 *input)
{
char v1; // dl
int a_0; // esi
int v3; // edi
int v4; // eax
int v5; // esi
int v6; // ebx
int v7; // esi
int v8; // eax
unsigned __int8 v9; // bl
int v10; // edi
int v11; // esi
int v12; // edx
int v13; // edi
int v14; // esi
int v15; // edi
int v16; // esi
int v17; // edi
int v18; // esi
int result; // eax
int v20; // [esp+Ch] [ebp-34h]
int v21; // [esp+10h] [ebp-30h]
int v22; // [esp+14h] [ebp-2Ch]
int v23; // [esp+18h] [ebp-28h]
int v24; // [esp+1Ch] [ebp-24h]
int v25; // [esp+24h] [ebp-1Ch]
int v26; // [esp+28h] [ebp-18h]
int v27; // [esp+2Ch] [ebp-14h]
int v28; // [esp+30h] [ebp-10h]
int v29; // [esp+34h] [ebp-Ch]
int v30; // [esp+38h] [ebp-8h]
int v31; // [esp+3Ch] [ebp-4h]
v1 = 1;
a_0 = *input;
v3 = input[2];
v31 = a_0;
v28 = v3;
v30 = input[1];
if ( 0xFFF9DEB8 * a_0 != 0xFFBC91E8 )
v1 = 0;
if ( 191967 * input[1] + 473999 * a_0 != 23642821 )
v1 = 0;
v4 = 57125 * a_0;
v5 = input[3];
v6 = input[4];
v29 = v5;
v27 = v6;
if ( v4 + 465507 * v30 - 207145 * v3 != 42831307 )
v1 = 0;
if ( 149773 * v5 + -488633 * v31 - 5245 * v30 - 280749 * v3 != -560637 )
v1 = 0;
if ( 381790 * v3 + 59135 * v6 + 130415 * v30 + 174205 * v5 - 83562 * v31 != 27764403 )
v1 = 0;
v7 = input[5];
v26 = v7;
v8 = 500139 * v6;
v9 = v1;
if ( 386908 * v31 + 465831 * v29 + v8 + 500998 * v7 + 474240 * v3 - 4838 * v30 != 119143813 )
v9 = 0;
v10 = input[6];
v25 = v10;
if ( 182991 * v29 + -200009 * v30 - 497601 * v31 - 153099 * v10 + 269682 * v27 + -269523 * v7 - 441164 * v28 != -52489521 )
v9 = 0;
v11 = input[7];
v23 = v11;
if ( -14894 * v11
- 162386 * v31
+ 522547 * v29
+ 260922 * v26
+ 428523 * v28
+ 508037 * v27
- 144626 * v30
- 99507 * v10 != 67497415 )
v9 = 0;
v12 = input[8];
if ( 51126 * v28
+ 145838 * v11
+ 362957 * v27
+ 43500 * v30
+ 308294 * v31
+ -375461 * v29
- 174341 * v12
- 394061 * v10
- 65395 * v26 != -43306962 )
v9 = 0;
v13 = input[9];
v24 = v13;
if ( 350654 * v31
+ 495127 * v27
+ 434878 * v11
- 75418 * v25
- 43467 * v30
+ -521005 * v26
- 226910 * v12
- 215985 * v13
- 121973 * v29
- 446107 * v28 != -137046349 )
v9 = 0;
v14 = input[10];
v22 = v14;
if ( -318934 * v30
- 25936 * v31
- 341583 * v12
+ 320416 * v28
+ 339525 * v23
- 81574 * v27
- 502348 * v25
- 294177 * v14
- 363326 * v29
- 391486 * v26
- 248464 * v13 != -244744603 )
v9 = 0;
v15 = input[11];
v21 = v15;
if ( 81654 * v23
+ 432919 * v25
+ 110106 * v12
- 507164 * v28
- 467060 * v26
+ -384845 * v15
- 197253 * v24
- 354555 * v30
- 16893 * v14
- 254110 * v31
- 479559 * v29
- 50999 * v27 != -214023755 )
v9 = 0;
v16 = input[12];
v20 = v16;
if ( -117388 * v24
- 227694 * v31
+ 457647 * v27
+ 293306 * v23
+ 101385 * v29
+ 293124 * v22
+ 92941 * v16
+ 496679 * v12
+ 79854 * v28
+ -81913 * v30
- 507308 * v26
- 3285 * v15
- 71736 * v25 != 50059304 )
v9 = 0;
v17 = input[13];
if ( 281406 * v28
+ 314118 * v27
+ -480916 * v23
- 124091 * v17
- 442447 * v22
- 25649 * v31
+ 389372 * v16
+ 15089 * v29
+ 210603 * v25
+ 5 * (v12 + 17363 * v26 - 91574 * v21)
- 469378 * v24
- 117744 * v30 != -176657564 )
v9 = 0;
v18 = input[14];
if ( 180059 * v25
+ 350603 * v31
+ -439557 * v21
- 485708 * v28
+ 52520 * v24
+ 303697 * v27
+ 395976 * v22
+ 406658 * v26
+ -354103 * v17
- 61339 * v20
- 495692 * v30
- 198340 * v29
- 28153 * v12
- 113385 * v23
- 492085 * v18 != -48802225 )
v9 = 0;
result = v9;
if ( 473763 * v12
+ 249640 * v25
+ 450341 * v29
+ 273347 * v17
+ 386739 * v30
+ 24246 * v26
+ 20430 * v21
+ 69055 * v27
+ 391476 * v22
+ 100872 * v23
+ 458039 * v20
+ 71004 * v24
+ -277369 * v28
- 482854 * input[15]
- 468152 * v31
- 409044 * v18 != 224749784 )
result = 0;
return result;
}
Z3解方程即可:
from z3 import *
v = [BitVec('v%d'%i,32) for i in range(16)]
solver = Solver()
solver.add(0xFFF9DEB8 * v[0] == 0xFFBC91E8)
solver.add(191967 * v[1] + 473999 * v[0] == 23642821)
solver.add(57125 * v[0] + 465507 * v[1] - 207145 * v[2] == 42831307)
solver.add(149773 * v[3] + 4294478663 * v[0] - 5245 * v[1] - 280749 * v[2] == 4294406659)
solver.add(381790 * v[2] + 59135 * v[4] + 130415 * v[1] + 174205 * v[3] - 83562 * v[0] == 27764403)
solver.add(386908 * v[0] + 465831 * v[3] + 500139 * v[4] + 500998 * v[5] + 474240 * v[2] - 4838 * v[1] == 119143813)
solver.add(182991 * v[3] + 4294767287 * v[1] - 497601 * v[0] - 153099 * v[6] + 269682 * v[4] + 4294697773 * v[5] - 441164 * v[2] == 4242477775)
solver.add(4294952402 * v[7]
- 162386 * v[0]
+ 522547 * v[3]
+ 260922 * v[5]
+ 428523 * v[2]
+ 508037 * v[4]
- 144626 * v[1]
- 99507 * v[6] == 67497415 )
solver.add(51126 * v[2]
+ 145838 * v[7]
+ 362957 * v[4]
+ 43500 * v[1]
+ 308294 * v[0]
+ 4294591835 * v[3]
- 174341 * v[8]
- 394061 * v[6]
- 65395 * v[5] == 4251660334 )
solver.add(350654 * v[0]
+ 495127 * v[4]
+ 434878 * v[7]
- 75418 * v[6]
- 43467 * v[1]
+ 4294446291 * v[5]
- 226910 * v[8]
- 215985 * v[9]
- 121973 * v[3]
- 446107 * v[2] == 4157920947 )
solver.add(4294648362 * v[1]
- 25936 * v[0]
- 341583 * v[8]
+ 320416 * v[2]
+ 339525 * v[7]
- 81574 * v[4]
- 502348 * v[6]
- 294177 * v[10]
- 363326 * v[3]
- 391486 * v[5]
- 248464 * v[9] == 4050222693 )
solver.add(81654 * v[7]
+ 432919 * v[6]
+ 110106 * v[8]
- 507164 * v[2]
- 467060 * v[5]
+ 4294582451 * v[11]
- 197253 * v[9]
- 354555 * v[1]
- 16893 * v[10]
- 254110 * v[0]
- 479559 * v[3]
- 50999 * v[4] == 4080943541 )
solver.add(4294849908 * v[9]
- 227694 * v[0]
+ 457647 * v[4]
+ 293306 * v[7]
+ 101385 * v[3]
+ 293124 * v[10]
+ 92941 * v[12]
+ 496679 * v[8]
+ 79854 * v[2]
+ 4294885383 * v[1]
- 507308 * v[5]
- 3285 * v[11]
- 71736 * v[6] == 50059304 )
solver.add(281406 * v[2]
+ 314118 * v[4]
+ 4294486380 * v[7]
- 124091 * v[13]
- 442447 * v[10]
- 25649 * v[0]
+ 389372 * v[12]
+ 15089 * v[3]
+ 210603 * v[6]
+ 5 * (v[8] + 17363 * v[5] - 91574 * v[11])
- 469378 * v[9]
- 117744 * v[1] == 4118309732 )
solver.add(180059 * v[6]
+ 350603 * v[0]
+ 4294527739 * v[11]
- 485708 * v[2]
+ 52520 * v[9]
+ 303697 * v[4]
+ 395976 * v[10]
+ 406658 * v[5]
+ 4294613193 * v[13]
- 61339 * v[12]
- 495692 * v[1]
- 198340 * v[3]
- 28153 * v[8]
- 113385 * v[7]
- 492085 * v[14] == 4246165071 )
solver.add(473763 * v[8]
+ 249640 * v[6]
+ 450341 * v[3]
+ 273347 * v[13]
+ 386739 * v[1]
+ 24246 * v[5]
+ 20430 * v[11]
+ 69055 * v[4]
+ 391476 * v[10]
+ 100872 * v[7]
+ 458039 * v[12]
+ 71004 * v[9]
+ 4294689927 * v[2]
- 482854 * v[15]
- 468152 * v[0]
- 409044 * v[14] == 224749784 )
for i in v:
solver.add(i<0x100)
solver.add(i>=0)
#solver.add(v[0]!=11)
if solver.check() == sat:
m = solver.model()
print m
r_flag = ''
for i in range(len(v)):
r_flag += '%02x'%(m[v[i]].as_long().real)
print r_flag
#flag{0b600c-3a198c-0e0891-9aa2ac765e0c7e}
该题是rop vm,直接看main:
跟进:
直接把rsp改成了data的地址,也就是切换了栈的位置:
data里面全是小gadget的地址,随便点开一个:
我使用的方法是直接在vm入口处开启trace,打印所有执行过的指令,分析得到程序的处理流程,然后使用Z3解决问题(Z3方程就代表了程序的检查逻辑,故不再重复写了):
from z3 import *
solver = Solver()
v = [[BitVec('v%d'%(4*i+j),8) for j in range(4)] for i in range(4)]
data = [0x64,0x25,0x0F,0x6C,0x20,0x23,0x8A,0xDE,0x10,0x0E,0xA5,0xE1,0x43,0x37,0x11,0x53]
for i in range(16):
data[i] ^= i
for g in range(4):
group = v[g]
b1 = group[0]
b2 = group[1]
b3 = group[2]
b4 = group[3]
solver.add((((2*b2)^b2)^((b3^b4)^(2*b1)))&0xff == data[g*4+0])
solver.add((((2*b3)^b3)^((b1^b4)^(2*b2)))&0xff == data[g*4+1])
solver.add((((2*b4)^b4)^((b1^b2)^(2*b3)))&0xff == data[g*4+2])
solver.add((((2*b1)^b1)^((b2^b3)^(2*b4)))&0xff == data[g*4+3])
if solver.check() == sat:
m = solver.model()
res = [0]*16
for i in range(4):
for j in range(4):
res[j*4+i] = chr(m[v[i][j]].as_long().real)
print 'ctf{'+''.join(res)+'}'
由于该题出题失误,导致也可以用angr直接跑出结果,这里不在赘述。
逆向程序要求输入MD5的md5等于给定:
int __cdecl main(int argc, const char **argv, const char **envp)
{
__m128i *v3; // ecx
int *v4; // edx
unsigned int v5; // esi
bool v6; // cf
int result; // eax
int v8[4]; // [esp+4h] [ebp-14h] BYREF
puts("Are you a philosopher?");
if ( argc <= 1 )
{
puts("Go away! You are not a philosopher!");
result = 0;
}
else
{
v3 = MD5(argv[1]);
v8[0] = 0x454C5C85;
v8[1] = 0x25C370D1;
v4 = v8;
v8[2] = 0xB3C707F0;
v5 = 12;
v8[3] = 0x57635121;
while ( v3->m128i_i32[0] == *v4 )
{
v3 = (__m128i *)((char *)v3 + 4);
++v4;
v6 = v5 < 4;
v5 -= 4;
if ( v6 )
{
puts("We found a philosopher!");
goto LABEL_6;
}
}
puts("Nice try");
LABEL_6:
result = 0;
}
return result;
}
去cmd5网站解密无果,后来查看程序资源:
发现FL4G资源是个格式被破坏PNG:
修复文件前四个字节即可:
打开图片即可获得flag:
发现题目exe可以直接解压:
运行run得到一个tif文件,并且通过逆向run,发现tif文件后追加了一段数据:
使用PS打开tif文件,发现移动图层可获得隐藏信息:
脑洞该信息表示之前的加密算法,于是写出解密:
本文作者:剑神
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/138050.html