每天一道re
Exeinfo PE查壳,可以用Linux打开
用kali打开,得到关键语句
用ida打开,找到main函数F5反编译
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v3; // eax
unsigned int v4; // ST38_4
__int64 v5; // rsi
signed int v7; // [rsp+2Ch] [rbp-54h]
char v8; // [rsp+40h] [rbp-40h]
int v9; // [rsp+78h] [rbp-8h]
int v10; // [rsp+7Ch] [rbp-4h]
v9 = 0;
printf("input your flag:", argv, envp);
gets(&v8);
v10 = general_inspection((int (*)[9])sudoku);
v7 = -1804515313;
while ( 1 )
{
while ( 1 )
{
while ( v7 == -2071121728 )
{
v4 = blank_num((int (*)[9])sudoku);
v5 = mem_alloc(v4);
trace(sudoku, v5, v4);
check((int (*)[9])sudoku);
check1(&v8);
check3(&v8);
v9 = 0;
v7 = -303742386;
}
if ( v7 != -1804515313 )
break;
v3 = -2071121728;
if ( v10 )
v3 = 664169471;
v7 = v3;
}
if ( v7 == -303742386 )
break;
if ( v7 == 664169471 )
{
printf("error");
check((int (*)[9])sudoku);
v9 = 0;
v7 = -303742386;
}
}
return v9;
}
输入的flag传入到v8,直接跟踪v8 ,发现传入了check1和check3,查看check1,用了ollvm,OLLVM(Obfuscator-LLVM)是瑞士西北应用科技大学安全实验室于2010年6月份发起的一个项目,这个项目的目标是提供一个LLVM编译套件的开源分支,能够通过代码混淆和防篡改,增加对逆向工程的难度,提供更高的软件安全性。
来自(47条消息) OLLVM分析_chrisnotfound-CSDN博客_ollvm
其实慢慢分析不断跟踪v10的值,就很快分析出了他其实就是三层加密操作
接下来就是check3,check3又套了一层check2加密操作
__int64 __fastcall check3(char *a1)
{
__int64 result; // rax
signed int v2; // eax
signed int v3; // [rsp+28h] [rbp-18h]
int v4; // [rsp+3Ch] [rbp-4h]
v4 = check2(a1);
v3 = 16123822;
while ( 1 )
{
while ( v3 == 16123822 )
{
v2 = 1478060410;
if ( !v4 )
v2 = 1274132590;
v3 = v2;
}
result = (unsigned int)(v3 - 824643665);
if ( v3 == 824643665 )
break;
if ( v3 == 1274132590 )
{
v3 = 824643665;
printf("error!\n");
}
else if ( v3 == 1478060410 )
{
v3 = 824643665;
printf("you get it!\n");
}
}
return result;
}
根据动态调试可以知道flag不正确会返回1,正确即为零,然后check3就会输出“you get it!”
看看check3,也是和check1同样的分析方法
第二层:D0g3[9 * v15 + v14] ==0时,将v16给了二维数组dog3,有点绕,我用了动态调试的方法,一开始查看dog3的值:
不对F8,得到
再去与v16的值进行对比,发现是v16的值给了dog3中零的位置
然后就密码核对用到的sudoku,查看main的函数发现有对sudoku进行操作,直接动态调试得到结果
最后的脚本为:
#include<stdio.h>
int main()
{
int a[81]={1,4,5,3,2,7,6,9,8,8,3,9,6,5,4,1,2,7,6,7,2,8,1,9,5,4,3,4,9,6,1,8,5,3,7,2,2,1,8,4,7,3,9,5,6,7,5,3,2,9,6,4,8,1,3,6,7,5,4,2,8,1,9,9,8,4,7,6,1,2,3,5,5,2,1,9,3,8,7,6,4};
int P[81]={1,0,5,3,2,7,0,0,8,8,0,9,0,5,0,0,2,0,0,7,0,0,1,0,5,0,3,4,9,0,1,0,0,3,0,0,0,1,0,0,7,0,9,0,6,7,0,3,2,9,0,4,8,0,0,6,0,5,4,0,8,0,9,0,0,4,0,0,1,0,3,0,0,2,1,0,3,0,7,0,4};
int R[40];//输入的flag
int o;
int L=0;
int temp;
for(int i=0;i<81;i++)
{
if(P[i]==0)
{R[L]=a[i]+232084296-232084248;L++;} //得到flag的密码表
}
for (int i = 0; i <40; i++) { temp = R[i] + 20; temp = temp & 0xf3 | ~temp & 0xc; R[i] = temp; }
//前后两个置换
for(int i=0;i<40;i=i+2)
{o = R[i]; R[i] = R[i+1]; R[i+1] = o;}
//前后两个部分置换
int g=40>>1;
for(int i=0;i<40>>1;i++,g++)
{o = R[i]; R[i] = R[g]; R[g] = o;}
for(int i=0;i<40;i++)
{printf("%c",R[i]);}
}
反思,在check2第二层加密中,没有想到用动态分析,导致静态分析错误,又浪费了时间。