软件破解尝试
這里我會講述一個在土耳其的安卡拉面試的故事。
“軟件安全工程師(Software Security Engineer)”——我申請的是這樣一個職位,面試時候他們問了我一些低級的問題,有些我能答上來,還有些卻不行。
然后他們給我發了一封郵件,其中包含了一個加密的程序(CRACK MEEE!)。回家之后我下載了它,打開發現需要一個密碼來解鎖,心想原來他們是要我找到這個密碼。:)
乍看之下這是相當困難的一件事,不過下面我會介紹破解過程中一些主要的概念。:)
第一件事就是在終端中執行程序
root@lisa:~# ./CrackTheDoor*** DOOR CONTROL SYSTEM ***PASSWORD:我隨手嘗試了幾個愚蠢的密碼,3次之后,它就退出了。:)
再嘗試用工具去分析它,比如獲取文件信息:
root@lisa:~# file CrackTheDoorCrackTheDoor: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),dynamically linked (uses shared libs), for GNU/Linux 2.6.15,BuildID[sha1]=0x9927be2fe310bea01d412164103b9c8b2d7567ea, not strippedroot@lisa:~#于是我們就得到了關于這個二進制包更詳細的信息:)
接下來:
root@lisa:~# ldd CrackTheDoorlinux-gate.so.1 => (0xf777b000)libc.so.6 => /lib32/libc.so.6 (0xf760c000)/lib/ld-linux.so.2 (0xf777c000)root@lisa:~#哎呀,順手就打了這個命令。我稍微解釋一下,linux-gate.so這個文件應該可以在你的電腦上找到。從ldd命令的結果可以看出它是一個共享庫對吧?那么你們聽說過Virtual DSO(Virtual Dynamic Shared Object)嗎?
這里建議閱讀一下關于的linux-gate.so詳細介紹。
libc.so.6是GNU系統上一個通用的C語言庫,這個你們可能都知道。
ld-linux.so是linux的動態加載器。
到目前為止一切都還算順利,那么使用調試器來運行這個程序試試:
root@lisa:~# gdb CrackTheDoorGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type “show copying”and “show warranty” for details.This GDB was configured as “x86_64-linux-gnu”.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>…Reading symbols from /root/CrackTheDoor…(no debugging symbols found)…done.(gdb) rStarting program: /root/CrackTheDoorProgram received signal SIGSEGV, Segmentation fault.0x080484fb in __do_global_dtors_aux ()(gdb)結果程序自己就掛掉了,應該是我們使用調試器造成的,看來有些反調試的小花招集成在里面了。那么……
我們來重新運行它,并且找到程序是從哪開始執行的:
root@lisa:~# gdb CrackTheDoorGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type “show copying”and “show warranty” for details.This GDB was configured as “x86_64-linux-gnu”.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>…Reading symbols from /root/CrackTheDoor…(no debugging symbols found)…done.(gdb) info fileSymbols from “/root/CrackTheDoor”.Local exec file:`/root/CrackTheDoor’, file type elf32-i386.Entry point: 0x804762c……這樣就得到了程序的入口,在這里設置一個斷點再調試看看:
b * 0x804762c按r運行,應該會停在入口的第一行:
gdb) x/30i $pc=> 0x804762c: pusha0x804762d: mov $0xaa,%dl0x804762f: mov $0×8048480,%edi0×8047634: mov $0x8048cbc,%ecx0×8047639: mov %edi,0x80476f30x804763f: mov %ecx,0x80476f70×8047645: sub %edi,%ecx0×8047647: mov $0x804762f,%esi0x804764c: push $0x80476c10×8047651: pusha0×8047652: mov $0×55,%al0×8047654: xor $0×99,%al0×8047656: mov $0×8047656,%edi0x804765b: mov $0x80476e5,%ecx0×8047660: sub $0×8047656,%ecx0×8047666: repnz scas %es:(%edi),%al0×8047668: je 0x804770a0x804766e: mov %edi,0x80476eb0×8047674: popa0×8047675: add 0x80476eb,%edx0x804767b: ret結果應該上面那樣的,這里語法系統是AT&A,你也可以切換為Intel語法體系。我個人而言,更偏向Intel語法。
在地址0×8047654處,我們首先吧0×55放到AL寄存器,然后將它和0×99異或,得到了0xCC。
0xCC非常重要,因為它會中斷你的進程,正如評論中所說,這在x86架構中是斷點指令(譯注:INT 3)。當調試器想要中斷程序時,會將0xCC這個字節放到需要斷點的地方。
在0×8047666處有個指令repnz scas,意思是在段寄存器ES和偏移量EDI范圍的內存中尋找AL里的值(0xCC)。
簡單來說,這行就是會搜尋內存中的0xCC,如果找到就讓程序掛掉。
不過我不想在這花費太多時間,我們來執行strace命令:
root@lisa:~# strace ./CrackTheDoorexecve(“./CrackTheDoor”, ["./CrackTheDoor"], [/* 17 vars */]) = 0[ Process PID=31085 runs in 32 bit mode. ]brk(0) = 0×9972000access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7715000access(“/etc/ld.so.preload”, R_OK) = -1 ENOENT (No such file or directory)open(“/etc/ld.so.cache”, O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=35597, …}) = 0mmap2(NULL, 35597, PROT_READ, MAP_PRIVATE, 3, 0) = 0xfffffffff770c000close(3) = 0access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)open(“/lib32/libc.so.6″, O_RDONLY) = 3read(3, “\177ELF\1\1\1\3\3\1\300o\1004″…, 512) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1441884, …}) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff770b000mmap2(NULL, 1456504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xfffffffff75a7000mprotect(0xf7704000, 4096, PROT_NONE) = 0mmap2(0xf7705000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15d) = 0xfffffffff7705000mmap2(0xf7708000, 10616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7708000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff75a6000set_thread_area(0xffe4d864) = 0mprotect(0xf7705000, 8192, PROT_READ) = 0mprotect(0×8049000, 4096, PROT_READ) = 0mprotect(0xf7733000, 4096, PROT_READ) = 0munmap(0xf770c000, 35597) = 0ptrace(PTRACE_TRACEME, 0, 0×1, 0) = -1 EPERM (Operation not permitted)ptrace(PTRACE_TRACEME, 0, 0×1, 0) = -1 EPERM (Operation not permitted)看到最后一行了吧,我們的程序又掛掉了,是ptrace這個函數的系統調用引起的。
在Linux中,ptrace是”Process Trace”的縮寫。有了它,你就可以控制另一個進程,并且改變執行狀態,就像調試器中一樣。
調試器經常使用ptrace:),畢竟這就是它們的任務嘛。
我們可以想象一下這段代碼,可能是下面這樣的:
int main() {if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {printf("DEBUGGING... Bye\n");return 1;}printf("Hello\n");return 0; }順便說一句,你只能使用一次ptrace[PTRACE_TRACEME]。因此如果調試器在這之前使用ptrace,那么我們的調用就會返回false,于是就能知道還有其他東西在控制程序了。
現在需要做的是繞過ptrace保護機制,使程序無法檢測到自己運行在調試器中。
所以一個可能的策略是改變這個系統調用的返回值。
系統調用是用戶態與核心態之間的橋梁,于是可以確定ptrace中一定用到了一些系統調用來控制進程。
我們希望檢測到程序使用ptrace,并且設置它的返回值為0:)
我在home目錄下建立了一個文件叫.gdbinit,這樣一來,當運行gdb的時候,其中的配置信息就會被自動加載。
~/.gdbinitset disassembly-flavor intel # Intel syntax is betterset disassemble-next-line oncatch syscall ptrace #Catch the syscall.commands 1set ($eax) = 0continueend寄存器EAX會保存系統調用的返回值,這樣它就永遠都是0了,或者說是true。
通過這種方式,我們繞過了反調試機制,那就回到gdb繼續吧:
eren@lisa:~$ gdb ./CrackTheDoorGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type “show copying”and “show warranty” for details.This GDB was configured as “x86_64-linux-gnu”.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>…Catchpoint 1 (syscall ‘ptrace’ [26])Reading symbols from /home/eren/CrackTheDoor…(no debugging symbols found)…done.(gdb) rStarting program: /home/eren/CrackTheDoorCatchpoint 1 (call to syscall ptrace), 0×08047698 in ?? ()=> 0×08047698: 3d 00 f0 ff ff cmp eax,0xfffff000Catchpoint 1 (returned from syscall ptrace), 0×08047698 in ?? ()=> 0×08047698: 3d 00 f0 ff ff cmp eax,0xfffff000*** DOOR CONTROL SYSTEM ***PASSWORD:好了,至少目前為止我們能夠隨心所欲地來調試了。:)
我在函數PJeGPC4TIVaKFmmy53DJ處又設置了一個斷點:
Breakpoint 2, 0×08048534 in PJeGPC4TIVaKFmmy53DJ ()=> 0×08048534 <PJeGPC4TIVaKFmmy53DJ+0>: 1e push ds(gdb) x/40i $pc=> 0×8048534 <PJeGPC4TIVaKFmmy53DJ>: push ds0×8048535 <PJeGPC4TIVaKFmmy53DJ+1>: mov ebp,esp0×8048537 <PJeGPC4TIVaKFmmy53DJ+3>: sub esp,0×200x804853a <PJeGPC4TIVaKFmmy53DJ+6>: mov BYTE PTR [ebp-0x1],0xe40x804853e <PJeGPC4TIVaKFmmy53DJ+10>: mov BYTE PTR [ebp-0x2],0×870×8048542 <PJeGPC4TIVaKFmmy53DJ+14>: mov BYTE PTR [ebp-0x3],0xfb0×8048546 <PJeGPC4TIVaKFmmy53DJ+18>: mov BYTE PTR [ebp-0x4],0xbe0x804854a <PJeGPC4TIVaKFmmy53DJ+22>: mov BYTE PTR [ebp-0x5],0xc90x804854e <PJeGPC4TIVaKFmmy53DJ+26>: mov BYTE PTR [ebp-0x6],0×930×8048552 <PJeGPC4TIVaKFmmy53DJ+30>: mov BYTE PTR [ebp-0x7],0×840×8048556 <PJeGPC4TIVaKFmmy53DJ+34>: mov BYTE PTR [ebp-0x8],0xfc0x804855a <PJeGPC4TIVaKFmmy53DJ+38>: mov BYTE PTR [ebp-0x9],0x8d0x804855e <PJeGPC4TIVaKFmmy53DJ+42>: mov BYTE PTR [ebp-0xa],0xe50×8048562 <PJeGPC4TIVaKFmmy53DJ+46>: mov BYTE PTR [ebp-0xb],0xbf0×8048566 <PJeGPC4TIVaKFmmy53DJ+50>: mov BYTE PTR [ebp-0xc],0x5c0x804856a <PJeGPC4TIVaKFmmy53DJ+54>: mov BYTE PTR [ebp-0xd],0xe20x804856e <PJeGPC4TIVaKFmmy53DJ+58>: mov BYTE PTR [ebp-0xe],0×760×8048572 <PJeGPC4TIVaKFmmy53DJ+62>: mov BYTE PTR [ebp-0xf],0×210×8048576 <PJeGPC4TIVaKFmmy53DJ+66>: mov BYTE PTR [ebp-0x10],0xb80x804857a <PJeGPC4TIVaKFmmy53DJ+70>: mov DWORD PTR [ebp-0x14],0×00×8048581 <PJeGPC4TIVaKFmmy53DJ+77>: mov eax,DWORD PTR [ebp-0x14]0×8048584 <PJeGPC4TIVaKFmmy53DJ+80>: add eax,DWORD PTR [ebp+0x8]0×8048587 <PJeGPC4TIVaKFmmy53DJ+83>: movzx eax,BYTE PTR [eax]0x804858a <PJeGPC4TIVaKFmmy53DJ+86>: test al,al0x804858c <PJeGPC4TIVaKFmmy53DJ+88>: je 0×8048808 <PJeGPC4TIVaKFmmy53DJ+724>0×8048592 <PJeGPC4TIVaKFmmy53DJ+94>: mov eax,DWORD PTR [ebp-0x14]0×8048595 <PJeGPC4TIVaKFmmy53DJ+97>: add eax,DWORD PTR [ebp+0x8]0×8048598 <PJeGPC4TIVaKFmmy53DJ+100>: mov edx,DWORD PTR [ebp-0x14]0x804859b <PJeGPC4TIVaKFmmy53DJ+103>: add edx,DWORD PTR [ebp+0x8]0x804859e <PJeGPC4TIVaKFmmy53DJ+106>: movzx edx,BYTE PTR [edx]0x80485a1 <PJeGPC4TIVaKFmmy53DJ+109>: xor dl,BYTE PTR [ebp-0x1]0x80485a4 <PJeGPC4TIVaKFmmy53DJ+112>: mov BYTE PTR [eax],dl0x80485a6 <PJeGPC4TIVaKFmmy53DJ+114>: add DWORD PTR [ebp-0x14],0×10x80485aa <PJeGPC4TIVaKFmmy53DJ+118>: mov eax,DWORD PTR [ebp-0x14]0x80485ad <PJeGPC4TIVaKFmmy53DJ+121>: add eax,DWORD PTR [ebp+0x8]0x80485b0 <PJeGPC4TIVaKFmmy53DJ+124>: movzx eax,BYTE PTR [eax]0x80485b3 <PJeGPC4TIVaKFmmy53DJ+127>: test al,al0x80485b5 <PJeGPC4TIVaKFmmy53DJ+129>: je 0x804880b <PJeGPC4TIVaKFmmy53DJ+727>0x80485bb <PJeGPC4TIVaKFmmy53DJ+135>: mov eax,DWORD PTR [ebp-0x14]0x80485be <PJeGPC4TIVaKFmmy53DJ+138>: add eax,DWORD PTR [ebp+0x8]0x80485c1 <PJeGPC4TIVaKFmmy53DJ+141>: mov edx,DWORD PTR [ebp-0x14]0x80485c4 <PJeGPC4TIVaKFmmy53DJ+144>: add edx,DWORD PTR [ebp+0x8]0x80485c7 <PJeGPC4TIVaKFmmy53DJ+147>: movzx edx,BYTE PTR [edx]0x80485ca <PJeGPC4TIVaKFmmy53DJ+150>: xor dl,BYTE PTR [ebp-0x2]終于到有樂子的步驟了。
我看到有些常量在內存中移動,并且和我輸入的值進行了異或運算。
繼續深入研究……
(gdb) x/30i X1bdrhN8Yk9NZ59Vb7P20×8048838 <X1bdrhN8Yk9NZ59Vb7P2>: sbb ecx,DWORD PTR [ecx+0x20ec83e5]0x804883e <X1bdrhN8Yk9NZ59Vb7P2+6>: mov DWORD PTR [ebp-0x18],0×00×8048845 <X1bdrhN8Yk9NZ59Vb7P2+13>: mov BYTE PTR [ebp-0x1],0xd90×8048849 <X1bdrhN8Yk9NZ59Vb7P2+17>: mov BYTE PTR [ebp-0x2],0xcd0x804884d <X1bdrhN8Yk9NZ59Vb7P2+21>: mov BYTE PTR [ebp-0x3],0xc90×8048851 <X1bdrhN8Yk9NZ59Vb7P2+25>: mov BYTE PTR [ebp-0x4],0xe50×8048855 <X1bdrhN8Yk9NZ59Vb7P2+29>: mov BYTE PTR [ebp-0x5],0x9e0×8048859 <X1bdrhN8Yk9NZ59Vb7P2+33>: mov BYTE PTR [ebp-0x6],0xd00x804885d <X1bdrhN8Yk9NZ59Vb7P2+37>: mov BYTE PTR [ebp-0x7],0xe80×8048861 <X1bdrhN8Yk9NZ59Vb7P2+41>: mov BYTE PTR [ebp-0x8],0xa50×8048865 <X1bdrhN8Yk9NZ59Vb7P2+45>: mov BYTE PTR [ebp-0x9],0xaf0×8048869 <X1bdrhN8Yk9NZ59Vb7P2+49>: mov BYTE PTR [ebp-0xa],0×870x804886d <X1bdrhN8Yk9NZ59Vb7P2+53>: mov BYTE PTR [ebp-0xb],0xd20×8048871 <X1bdrhN8Yk9NZ59Vb7P2+57>: mov BYTE PTR [ebp-0xc],0×790×8048875 <X1bdrhN8Yk9NZ59Vb7P2+61>: mov BYTE PTR [ebp-0xd],0xa90×8048879 <X1bdrhN8Yk9NZ59Vb7P2+65>: mov BYTE PTR [ebp-0xe],0x5d0x804887d <X1bdrhN8Yk9NZ59Vb7P2+69>: mov BYTE PTR [ebp-0xf],0×70×8048881 <X1bdrhN8Yk9NZ59Vb7P2+73>: mov BYTE PTR [ebp-0x10],0×810×8048885 <X1bdrhN8Yk9NZ59Vb7P2+77>: mov DWORD PTR [ebp-0x14],0×00x804888c <X1bdrhN8Yk9NZ59Vb7P2+84>: mov eax,DWORD PTR [ebp-0x14]0x804888f <X1bdrhN8Yk9NZ59Vb7P2+87>: add eax,DWORD PTR [ebp+0x8]0×8048892 <X1bdrhN8Yk9NZ59Vb7P2+90>: movzx eax,BYTE PTR [eax]0×8048895 <X1bdrhN8Yk9NZ59Vb7P2+93>: cmp al,BYTE PTR [ebp-0x1]0×8048898 <X1bdrhN8Yk9NZ59Vb7P2+96>: je 0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106>0x804889a <X1bdrhN8Yk9NZ59Vb7P2+98>: mov eax,DWORD PTR [ebp-0x18]和之前得到的結果類似,現在我在其中增加一些常量:
下面是這個函數后面運行的情況:
0x804889d <X1bdrhN8Yk9NZ59Vb7P2+101>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>0x80488a2 <X1bdrhN8Yk9NZ59Vb7P2+106>: add DWORD PTR [ebp-0x14],0×10x80488a6 <X1bdrhN8Yk9NZ59Vb7P2+110>: mov eax,DWORD PTR [ebp-0x14]0x80488a9 <X1bdrhN8Yk9NZ59Vb7P2+113>: add eax,DWORD PTR [ebp+0x8]0x80488ac <X1bdrhN8Yk9NZ59Vb7P2+116>: movzx eax,BYTE PTR [eax]0x80488af <X1bdrhN8Yk9NZ59Vb7P2+119>: cmp al,BYTE PTR [ebp-0x2]0x80488b2 <X1bdrhN8Yk9NZ59Vb7P2+122>: je 0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132>0x80488b4 <X1bdrhN8Yk9NZ59Vb7P2+124>: mov eax,DWORD PTR [ebp-0x18]0x80488b7 <X1bdrhN8Yk9NZ59Vb7P2+127>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>0x80488bc <X1bdrhN8Yk9NZ59Vb7P2+132>: add DWORD PTR [ebp-0x14],0×10x80488c0 <X1bdrhN8Yk9NZ59Vb7P2+136>: mov eax,DWORD PTR [ebp-0x14]0x80488c3 <X1bdrhN8Yk9NZ59Vb7P2+139>: add eax,DWORD PTR [ebp+0x8]0x80488c6 <X1bdrhN8Yk9NZ59Vb7P2+142>: movzx eax,BYTE PTR [eax]0x80488c9 <X1bdrhN8Yk9NZ59Vb7P2+145>: cmp al,BYTE PTR [ebp-0x3]0x80488cc <X1bdrhN8Yk9NZ59Vb7P2+148>: je 0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158>0x80488ce <X1bdrhN8Yk9NZ59Vb7P2+150>: mov eax,DWORD PTR [ebp-0x18]0x80488d1 <X1bdrhN8Yk9NZ59Vb7P2+153>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>0x80488d6 <X1bdrhN8Yk9NZ59Vb7P2+158>: add DWORD PTR [ebp-0x14],0×10x80488da <X1bdrhN8Yk9NZ59Vb7P2+162>: mov eax,DWORD PTR [ebp-0x14]0x80488dd <X1bdrhN8Yk9NZ59Vb7P2+165>: add eax,DWORD PTR [ebp+0x8]—Type <return> to continue, or q <return> to quit—0x80488e0 <X1bdrhN8Yk9NZ59Vb7P2+168>: movzx eax,BYTE PTR [eax]0x80488e3 <X1bdrhN8Yk9NZ59Vb7P2+171>: cmp al,BYTE PTR [ebp-0x4]0x80488e6 <X1bdrhN8Yk9NZ59Vb7P2+174>: je 0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184>0x80488e8 <X1bdrhN8Yk9NZ59Vb7P2+176>: mov eax,DWORD PTR [ebp-0x18]0x80488eb <X1bdrhN8Yk9NZ59Vb7P2+179>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>0x80488f0 <X1bdrhN8Yk9NZ59Vb7P2+184>: add DWORD PTR [ebp-0x14],0×10x80488f4 <X1bdrhN8Yk9NZ59Vb7P2+188>: mov eax,DWORD PTR [ebp-0x14]0x80488f7 <X1bdrhN8Yk9NZ59Vb7P2+191>: add eax,DWORD PTR [ebp+0x8]0x80488fa <X1bdrhN8Yk9NZ59Vb7P2+194>: movzx eax,BYTE PTR [eax]0x80488fd <X1bdrhN8Yk9NZ59Vb7P2+197>: cmp al,BYTE PTR [ebp-0x5]0×8048900 <X1bdrhN8Yk9NZ59Vb7P2+200>: je 0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210>0×8048902 <X1bdrhN8Yk9NZ59Vb7P2+202>: mov eax,DWORD PTR [ebp-0x18]0×8048905 <X1bdrhN8Yk9NZ59Vb7P2+205>: jmp 0x8048a20 <X1bdrhN8Yk9NZ59Vb7P2+488>0x804890a <X1bdrhN8Yk9NZ59Vb7P2+210>: add DWORD PTR [ebp-0x14],0×10x804890e <X1bdrhN8Yk9NZ59Vb7P2+214>: mov eax,DWORD PTR [ebp-0x14]你們看出其中運行的模式了嗎?如果沒看出來也沒關系……
在這個函數中,程序同樣將我的輸入和一些常量進行了異或運算。
現在來看看輸入,首先輸入會和這些常量進行異或,然后將結果和另一些常量進行對比。
因此這兩個函數應該是這樣的:
void PJeGPC4TIVaKFmmy53DJ (int * p) {int array[] = {0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8}for(i=0;i<16;i++){p[i] = p[i] ^ array[i]} }int X1bdrhN8Yk9NZ59Vb7P2(int * p) {int array = {0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81}for(i=0;i<16;i++){if(p[i] != array[i])return false; // fail..}return true }于是寫了一個簡單的python腳本將上面兩個常量進行異或操作,就得到密碼了:
#!/usr/bin/pythonfirstConst = [0xe4,0x87,0xfb,0xbe,0xc9,0x93,0x84,0xfc,0x8d,0xe5,0xbf,0x5c,0xe2,0x76,0x21,0xb8]secondConst = [0xd9,0xcd,0xc9,0xe5,0x9e,0xd0,0xe8,0xa5,0xaf,0x87,0xd2,0x79,0xa9,0x5d,0x7,0x81]ret =”"for x in range(16):ret+=chr(firstConst[x] ^ secondConst[x])print reteren@lisa:~$ ./CrackTheDoor*** DOOR CONTROL SYSTEM ***PASSWORD: =J2[WClY”bm%K+&9*** ACCESS GRANTED ****** THE DOOR OPENED ***看!成功了!
這個公司又給我發來了第二輪的破解題目,也一樣很有趣,下次我會在文章中寫到的。
譯注:原文評論中較多的疑問是如何定位到函數PJeGPC4TIVaKFmmy53DJ,有人給出了合理的解釋,作者也默認了:其實很簡單,不停地嘗試。也許寫下這篇文章之前有很多很多次失敗,但是讀者最感興趣的部分是成功的,因此那些都被省略了。
總結
- 上一篇: 读取xml文件转成ListT对象的两种方
- 下一篇: HDU 4777 Rabbit King