breakpoint
來源:http://ctf.idf.cn/index.php?g=game&m=article&a=index&id=46
請看這裏: http://pan.baidu.com/s/1pJyUYEZ
下載後得到一個文件:Elfcrackme2
本題分析
我的思路受以下文章啓發,表示誠摯謝意:
- 破解我吧:一次ELF文件的解構之旅 http://blog.csdn.net/fisher_jiang/article/details/6783922
- Linux程序調試–查看二進制文件 http://blog.sina.com.cn/s/blog_7a2fc53a0100y54h.html
- LINUX ELF文件動態加載調試 http://bbs.pediy.com/showthread.php?p=1216479&mode=threaded
1.又是一個elf執行文件,還是用idapro64打開它,如下圖:
另外,有幾個linux下的命令,雖然對於解本題意義不如idapro的用處大,但作爲linux自帶的程序員工具,還是說說:
- readelf
- 該命令是Linux下的分析ELF文件的命令,這個命令在分析ELF文件格式時非常有用
- 命令格式:readelf elf文件名
- strings
- 可以打印出文件中所有列出的可打印字符串
- 格式:strings 文件名
- file
- 用於檢測文件類型
- 格式:file 文件名
- gdb
- 用於調試linux下程序
- 命令參數太多,最簡單:gdb 文件名
objdump
- 用於輸出可執行文件的彙編代碼
- 格式:objdump -D 可執行文件名 > out.asm
效果如下圖:
readelf命令
file命令
strings命令
2.遍歷點擊左側函數名,查看右側內容,發現有個名爲sub_80483B0的函數裏面內容有我們關注的類似“flag…”輸出語句。按F4調用cpp反編譯插件,如下圖:
值得分析的關鍵代碼如下:
unsigned char g8049908 = 0xff;
unsigned char g80498f0 = 24;
unsigned char g8049909 = 0xff;
unsigned char g80498f1 = 91;
unsigned char g804990a = 0xff;
unsigned char g80498f2 = 0xbf;
signed char g804990b = -1;
signed char g80498f3 = 56;
signed char g804990c = -1;
signed char g80498f4 = 52;
signed char g804990d = -1;
signed char g80498f5 = 90;
signed char g804990e = -1;
signed char g80498f6 = 0x99;
signed char g804990f = -1;
signed char g80498f7 = 77;
signed char g8049910 = -1;
signed char g80498f8 = 46;
signed char g8049911 = -1;
signed char g80498f9 = 0x73;
signed char g8049912 = -1;
signed char g80498fa = -69;
signed char g8049913 = -1;
signed char g80498fb = 78;
uint32_t g8049914 = 0xffffffff;
signed char g80498fc = 35;
unsigned char g80498fd = 0x76;
unsigned char g80498fe = 0x9f;
unsigned char g80498ff = 3;
...
void sub_80483B0() {
signed char* ebx1;
uint32_t eax2;
signed char* edx3;
uint32_t edx4;
uint32_t v5;
uint32_t edx6;
uint32_t ecx7;
uint32_t ecx8;
uint32_t ebx9;
uint32_t edi10;
uint32_t ebx11;
uint32_t ebx12;
uint32_t ebx13;
uint32_t ebx14;
uint32_t ebx15;
uint32_t ebx16;
uint32_t ebx17;
uint32_t ebx18;
uint32_t ebx19;
uint32_t eax20;
uint32_t ebx21;
printf("%s\nPlease input your flag:", g8049900);
__isoc99_scanf("%s", 0x8049908);
ebx1 = g8049900;
eax2 = (uint32_t)ebx1 - (uint32_t)sub_80483B0;
if ((uint32_t)ebx1 > (uint32_t)sub_80483B0) {
edx3 = (signed char*)sub_80483B0;
do {
++edx3;
eax2 = eax2 << 5 ^ (uint32_t)((int32_t)eax2 >> 27) ^ (uint32_t)(unsigned char)*edx3;
} while (edx3 != ebx1);
}
edx4 = eax2;
v5 = eax2;
if ((*(unsigned char*)&edx4 ^ g8049908) != g80498f0 || ((edx6 = (uint32_t)(unsigned char)*((signed char*)&v5 + 1), ecx7 = edx6, (*(unsigned char*)&ecx7 ^ g8049909) != g80498f1) || ((ecx8 = (uint32_t)(unsigned char)*((signed char*)&v5 + 2), ebx9 = ecx8, (*(unsigned char*)&ebx9 ^ g804990a) != g80498f2) || ((edi10 = (uint32_t)(unsigned char)*((signed char*)&v5 + 3), ebx11 = (uint32_t)(unsigned char)g804990b ^ edi10, *(signed char*)&ebx11 != g80498f3) || ((ebx12 = (uint32_t)(unsigned char)g804990c ^ eax2, *(signed char*)&ebx12 != g80498f4) || ((ebx13 = (uint32_t)(unsigned char)g804990d ^ edx6, *(signed char*)&ebx13 != g80498f5) || ((ebx14 = (uint32_t)(unsigned char)g804990e ^ ecx8, *(signed char*)&ebx14 != g80498f6) || ((ebx15 = (uint32_t)(unsigned char)g804990f ^ edi10, *(signed char*)&ebx15 != g80498f7) || ((ebx16 = (uint32_t)(unsigned char)g8049910 ^ eax2, *(signed char*)&ebx16 != g80498f8) || ((ebx17 = (uint32_t)(unsigned char)g8049911 ^ edx6, *(signed char*)&ebx17 != g80498f9) || ((ebx18 = (uint32_t)(unsigned char)g8049912 ^ ecx8, *(signed char*)&ebx18 != g80498fa) || ((ebx19 = (uint32_t)(unsigned char)g8049913 ^ edi10, *(signed char*)&ebx19 != g80498fb) || ((eax20 = eax2 ^ g8049914, *(signed char*)&eax20 != g80498fc) || ((*(unsigned char*)&edx6 ^ *((unsigned char*)&g8049914 + 1)) != g80498fd || ((*(unsigned char*)&ecx8 ^ *((unsigned char*)&g8049914 + 2)) != g80498fe || (ebx21 = edi10, (*(unsigned char*)&ebx21 ^ *((unsigned char*)&g8049914 + 3)) != g80498ff)))))))))))))))) {
puts("You are wrong", 0x8049908);
} else {
puts("You are right", 0x8049908);
}
return;
}
3.先分析一下輸出“You are wrong”前if語句表達式的含義,由於裏面進行異或運算,所以要留意一下變量佔的字節數(這裏都是一個字節),如果變量字節都是1Byte,那麼很長的if表達式就可簡化爲下列表達式:
if ((edx4 ^ 0xff ) != 24
|| ((edx6 = v5 + 1), ecx7 = edx6, (ecx7 ^ 0xff) != 91)
|| ((ecx8 = v5 + 2), ebx9 = ecx8, (ebx9 ^ 0xff) != 0xbf)
|| ((edi10 = v5 + 3), ebx11 = -1 ^ edi10, ebx11 != 56)
|| ((ebx12 = -1 ^ eax2, ebx12 != 52)
|| ((ebx13 = -1 ^ edx6, ebx13 != 90)
|| ((ebx14 = -1 ^ ecx8, ebx14 != 0x99)
|| ((ebx15 = -1 ^ edi10, ebx15 != 77)
|| ((ebx16 = -1 ^ eax2, ebx16 != 98f8)
|| ((ebx17 = -1 ^ edx6, ebx17 != 0x73)
|| ((ebx18 = -1 ^ ecx8, ebx18 != -69)
|| ((ebx19 = -1 ^ edi10,ebx19 != 78)
|| ((eax20 = eax2 ^ 0xffffffff, eax20 != 35)
|| ((*(unsigned char*)&edx6 ^ *((unsigned char*)&0xffffffff + 1)) != 0x76
|| ((*(unsigned char*)&ecx8 ^ *((unsigned char*)&0xffffffff + 2)) != 0x9f
|| (ebx21 = edi10, (*(unsigned char*)&ebx21 ^ *((unsigned char*)&0xffffffff + 3)) != 3)
)
)
)
)
)
)
)
)
)
)
)
)
{
puts("You are wrong", 0x8049908);
} else {
puts("You are right", 0x8049908);
}
return;
我做了幾天,都沒有找出線索,現在記錄一下中間結果,期待後期進步後解決
edx2 = 231
-----
edx4 = 231
edx6 = 164
edx7 = 164
edx9 = 40 (
ebx11 = 56 8
ebx12 = 52 4
ebx13 = 90 Z
ebx14 = 153
ebx15 = 77 M
ebx16 = 46 .
ebx17 = 115 s
ebx18 = -69
ebx19 = 78 N
eax20 =35 #
g8049914 = edx2 xor eax20 = 196 即0xffffffff
即0xffffffff 210
ecx8 xor