用PEid查不出来, 用Exeinfo PE可以查出ELF文件的壳
用工具直接脱upx壳, kali自带的工具或者手动安装一个windows的upx工具
脱壳之后拖入IDA32
int __cdecl main(int argc, const char **argv, const char **envp)
{
int pipedes[2]; // [esp+18h] [ebp-38h] BYREF
__pid_t v5; // [esp+20h] [ebp-30h]
int v6; // [esp+24h] [ebp-2Ch] BYREF
char buf[30]; // [esp+2Eh] [ebp-22h] BYREF
unsigned int v8; // [esp+4Ch] [ebp-4h]
v8 = __readgsdword(0x14u);
pipe(pipedes);
v5 = fork(); // subprocess fpid
if ( !v5 ) // if subprocess then execute
{
puts("\nOMG!!!! I forgot kid's id");
write(pipedes[1], "69800876143568214356928753", 0x1Du);
puts("Ready to exit ");
exit(0);
}
read(pipedes[0], buf, 0x1Du); // subprocess input 69800876143568214356928753
__isoc99_scanf("%d", &v6);
if ( v6 == v5 )
{
if ( (unsigned __int8)*(_DWORD *)((char *)lol + 3) == 204 )
{
puts(":D");
exit(1);
}
printf("\nYou got the key\n ");
lol(buf);
}
wait(0);
return 0;
}
这是一个linux系统编程的逆向, 需要fork和进程间通信的知识, 系统编程和软件开发是做逆向的基本功, 所以需要补这方面的知识, 就不多说了 (面向搜索引擎做逆向也是基本功, 什么不懂现场学就完了
首先fork()
是返回创建的子进程的进程id, 子进程fpid是0, 父进程则保存子进程的fpid, 所以下面的代码只有子进程会执行
if ( !v5 ) // if subprocess then execute
{
puts("\nOMG!!!! I forgot kid's id");
write(pipedes[1], "69800876143568214356928753", 0x1Du);
puts("Ready to exit ");
exit(0);
}
pipe(pipedes);
是创建父子进程之间的通信管道, pipedes[0]是读, pipedes[1]是写
read(pipedes[0], buf, 0x1Du);
即父进程从管道读取0x1D的数据到buf
缓冲区
write(pipedes[1], "69800876143568214356928753", 0x1Du);
是子进程将"69800876143568214356928753"
写入管道, 所以父进程读出来的就是这一串
跟如lol()
函数发现反编译和汇编代码不一致, 这里就是涉及IDA反汇编的优化操作, 如果一段汇编代码被强制跳转略过, 根本不会被执行, 那么IDA的F5就不会反编译这段汇编代码, 所以看到的伪代码就是一行printf
用IDApython nop掉0x080486B0
地址的汇编指令, 这里如果是IDA7.5+版本, 因为API改了, 所以需要加一句from idc_bc695 import *
再F5即可反编译完整汇编
int __cdecl lol(_BYTE *buf)
{
int result; // eax
char flag[7]; // [esp+15h] [ebp-13h] BYREF
int v3; // [esp+1Ch] [ebp-Ch]
flag[0] = 2 * buf[1];
flag[1] = buf[4] + buf[5];
flag[2] = buf[8] + buf[9];
flag[3] = 2 * buf[12];
flag[4] = buf[18] + buf[17];
flag[5] = buf[10] + buf[21];
flag[6] = buf[9] + buf[25];
if ( v3 == 1 )
result = printf("%s", flag);
else
result = printf("flag_is_not_here");
return result;
}
阅读F5出来的伪代码, 即可知道flag就是69800876143568214356928753
处理出来的7字节串, 直接用cpp写逆
#include
#include
using namespace std;
int main () {
string flag(7, '0');
string buf = "69800876143568214356928753";
flag[0] = 2 * buf[1];
flag[1] = buf[4] + buf[5];
flag[2] = buf[8] + buf[9];
flag[3] = 2 * buf[12];
flag[4] = buf[18] + buf[17];
flag[5] = buf[10] + buf[21];
flag[6] = buf[9] + buf[25];
cout << "RCTF{" << flag << '}' << endl;
}
搞定~