1. 程式人生 > >面試官在面試時讓我去破解一個軟體,我成功了----linux破解

面試官在面試時讓我去破解一個軟體,我成功了----linux破解

最近我在面試中被要求破解一個程式,並且成功拿到了工作。

大家好,開了一個新部落格我真是非常激動吶,於是我計劃每週都要更新幾篇文章。看了標題各位應該知道本文的大概內容了,這裡我會講述一個在土耳其的安卡拉麵試的故事。

“軟體安全工程師(Software Security Engineer)”——我申請的是這樣一個職位,面試時候他們問了我一些低階的問題,有些我能答上來,還有些卻不行。

然後他們給我發了一封郵件,其中包含了一個加密的程式(CRACK MEEE!)。回家之後我下載了它,打開發現需要一個密碼來解鎖,心想原來他們是要我找到這個密碼。:)

乍看之下這是相當困難的一件事,不過下面我會介紹破解過程中一些主要的概念。:)

第一件事就是在終端中執行程式

[email protected]:~# ./CrackTheDoor

*** DOOR CONTROL SYSTEM ***

PASSWORD:

我隨手嘗試了幾個愚蠢的密碼,3次之後,它就退出了。:)

再嘗試用工具去分析它,比如獲取檔案資訊:

[email protected]:~# file CrackTheDoor

CrackTheDoor: 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 stripped [email protected]:~#

於是我們就得到了關於這個二進位制包更詳細的資訊:)

接下來:

[email protected]:~# ldd CrackTheDoor

linux-gate.so.1 => (0xf777b000)

libc.so.6 => /lib32/libc.so.6 (0xf760c000)

/lib/ld-linux.so.2 (0xf777c000)

[email protected]
:~#

哎呀,順手就打了這個命令。我稍微解釋一下,linux-gate.so這個檔案應該可以在你的電腦上找到。從ldd命令的結果可以看出它是一個共享庫對吧?那麼你們聽說過Virtual DSO(Virtual Dynamic Shared Object)嗎?

這裡建議閱讀一下關於的linux-gate.so詳細介紹

libc.so.6是GNU系統上一個通用的C語言庫,這個你們可能都知道。

ld-linux.so是linux的動態載入器。

到目前為止一切都還算順利,那麼使用偵錯程式來執行這個程式試試:

[email protected]:~# gdb CrackTheDoor

GNU gdb (GDB) 7.4.1-debian

Copyright (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) r

Starting program: /root/CrackTheDoorProgram received signal SIGSEGV, Segmentation fault.

0x080484fb in __do_global_dtors_aux ()

(gdb)

結果程式自己就掛掉了,應該是我們使用偵錯程式造成的,看來有些反除錯的小花招整合在裡面了。那麼……

我們來重新執行它,並且找到程式是從哪開始執行的:

[email protected]:~# gdb CrackTheDoor

GNU gdb (GDB) 7.4.1-debian

Copyright (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 file

Symbols from “/root/CrackTheDoor”.

Local exec file:

`/root/CrackTheDoor’, file type elf32-i386.

Entry point: 0x804762c

…

…

這樣就得到了程式的入口,在這裡設定一個斷點再除錯看看:

b * 0x804762c

按r執行,應該會停在入口的第一行:

gdb) x/30i $pc

=> 0x804762c: pusha

0x804762d: mov $0xaa,%dl

0x804762f: mov $0×8048480,%edi

0×8047634: mov $0x8048cbc,%ecx

0×8047639: mov %edi,0x80476f3

0x804763f: mov %ecx,0x80476f7

0×8047645: sub %edi,%ecx

0×8047647: mov $0x804762f,%esi

0x804764c: push $0x80476c1

0×8047651: pusha

0×8047652: mov $0×55,%al

0×8047654: xor $0×99,%al

0×8047656: mov $0×8047656,%edi

0x804765b: mov $0x80476e5,%ecx

0×8047660: sub $0×8047656,%ecx

0×8047666: repnz scas %es:(%edi),%al

0×8047668: je 0x804770a

0x804766e: mov %edi,0x80476eb

0×8047674: popa

0×8047675: add 0x80476eb,%edx

0x804767b: 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命令:

[email protected]:~# strace ./CrackTheDoor

execve(“./CrackTheDoor”, ["./CrackTheDoor"], [/* 17 vars */]) = 0

[ Process PID=31085 runs in 32 bit mode. ]

brk(0) = 0×9972000

access(“/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) = 0xfffffffff7715000

access(“/etc/ld.so.preload”, R_OK) = -1 ENOENT (No such file or directory)

open(“/etc/ld.so.cache”, O_RDONLY) = 3

fstat64(3, {st_mode=S_IFREG|0644, st_size=35597, …}) = 0

mmap2(NULL, 35597, PROT_READ, MAP_PRIVATE, 3, 0) = 0xfffffffff770c000

close(3) = 0

access(“/etc/ld.so.nohwcap”, F_OK) = -1 ENOENT (No such file or directory)

open(“/lib32/libc.so.6″, O_RDONLY) = 3

read(3, “\177ELF\1\1\1\3\3\1\300o\1004″…, 512) = 512

fstat64(3, {st_mode=S_IFREG|0755, st_size=1441884, …}) = 0

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff770b000

mmap2(NULL, 1456504, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xfffffffff75a7000

mprotect(0xf7704000, 4096, PROT_NONE) = 0

mmap2(0xf7705000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15d) = 0xfffffffff7705000

mmap2(0xf7708000, 10616, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xfffffffff7708000

close(3) = 0

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff75a6000

set_thread_area(0xffe4d864) = 0

mprotect(0xf7705000, 8192, PROT_READ) = 0

mprotect(0×8049000, 4096, PROT_READ) = 0

mprotect(0xf7733000, 4096, PROT_READ) = 0

munmap(0xf770c000, 35597) = 0

ptrace(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