一個簡單的linux crackme的逆向
阿新 • • 發佈:2019-01-03
前言
最不喜歡的就是寫破解教程,酒後一時衝動,老夫卿發少年狂,許下將寫一篇linux平臺逆向的文章的諾言,作此文實非頗不得已。
在此申明:本文在技術上非常初級,並沒有用到什麼高深的技術,本人水平亦有限,如有差錯,還請見諒!
開始之前的準備
正如C語言教程從 hello world 開始,我們也由一個 crackme 說開去。本文的例子程式你可以到這來下載:
http://www.crackmes.de/users/veneta/crackmes/linux_crackme_v2 。古人云“工欲善其事,必先利其器”,本文中所用到的工具及操作平臺羅列如下:
操作平臺: gentoo 2004.3 # kernel 2.6.9
逆向工具:
反彙編 -- objdump (這個工具基本上每個LINUX上都有)、lida( http://lida.sourceforge.net/ )
偵錯程式 -- gdb
十六進位制編輯器 -- hexedit
文字編輯器 -- vim
壓縮工具 -- upx (http://upx.sourceforge.net)
計算器 -- gcalctool(gnome計算器)
開始逆向之旅
首先我們看看程式基本資訊:
開啟控制檯,切換到程式所在目錄。執行“ objdump -x cm2 ”,顯示如下:
程式碼:
我們可以看到start address是0x08048080,但有一個問題是Sections下面卻什麼都沒有。這不是一個正常的程式?
接下來,使用十六進位制工具 hexedit 檢視程式資訊。執行命令:hexedit cm2 ,顯示如下:
程式碼:
執行命令“ upx -d cm2 ”把程式解壓縮,顯示如下:
程式碼:
程式碼:
我們再進一步的檢視程式資訊,執行命令“objdump -T cm2 >iat.txt”,下面的資訊將會儲存到iat.txt檔案中。
程式碼:
接下來,用VI開啟disasm.txt檔案。顯示如下:
相對WINDOW平臺的反彙編器,objdump 的反彙編結果在沒有除錯符號的情況下,不顯示API的名字。下一步API呼叫手工的加上。
我們開啟iat.txt檔案,把disasm.txt檔案中的地址全部轉換成函式名,例如:
程式碼:
這樣將好看多了。這一點你可以寫個指令碼自動完成,而不用手工一個一個的替換。或者你也可以使用更強大的反彙編工器lida來自動顯示API呼叫名。為了方便初學者,下面使用LIDA來作為反彙編工具。用lida 載入程式,如下圖:
好了,前期的工作都做了。下面讓我們來執行一下程式,看看有沒有什麼值得參考的。執行後,出現一個視窗。如下:
如圖,提示我們的CRACK任務之一就是NOP掉這個視窗。點選關閉按鈕,出現第二個視窗,如下圖
這是註冊的主視窗。
對照LIDA中的反彙編程式碼加上GTK的一些基本知識,我們可以知道程式執行過程是這樣的:main->跳出killme視窗->註冊destroy事件處理函式->在關閉 killme 視窗時將引發destroy事件->執行回撥處理函式0x80489bd->跳出crackme視窗。
我們CRACK的任務就是nop掉killme視窗,以及找出註冊碼。
注:GTK的相關文件你可以到這來獲取 http://www.gtk.org/tutorial/
第一個任務:去除killme視窗。
用lida反彙編cm2,點選選單 view -> Functions 找到main函式,點選進入,如下所示:
程式碼:
程式碼:
為了去除這個killme視窗。我們可以在 程式碼:
程式碼:
好的,下面我們就改08048988處的指令為 call 080489BD ,用計算器算一下:80489BD-08048988-5=00000030,得到程式碼為 e8 30 00 00 00 。嘿嘿!
好的,用hexedit 開啟 cm2 程式。看看前面objdump -x cm2列出的基地址為0x8048000,所以對應的file offset應該是0x8048988-0x8048000=0x988,我們按 return 鍵,開啟 go to 視窗,輸入 0x988 ,定位到08048988處,改程式碼為e830000000。改完後,“ ./cm2 ”執行程式,OK。出現 crackme 視窗了。
第二個任務,找出正確的註冊碼。
為保持本文一個苗條的身材及加大本文所包含的資訊量,我就不講怎麼根據按鈕名找對應的點選事件處理函數了,講一種簡單省事的方法,找註冊碼最省事的方法當然是動態跟蹤啦。搞不好還可以看到明碼喲。費話不多說,執行命令: gdb cm2 。提示沒有符號檔案,不用管它。
下斷點:
程式碼:
輸入名字和註冊碼,我這用的是:
名字:ncc2008
註冊碼:78787878
按crackme按鈕,中斷到gdb中。
程式碼:
程式碼:
程式碼:
程式中斷到我們所下的斷點0x8048cc1處。讓我們看看彙編程式碼:
下命令:x /10i $eip
顯示如下:
程式碼:
程式碼:
接下來,我們就一步一步跟吧!整個過程單調無趣,不多說了。註冊碼必需是32位,我使用“12345678abcdef0123456789abcdef0”
跟蹤其流程:
轉換註冊碼“12345678abcdef0123456789abcdef0”為:
程式碼:
程式碼:
程式碼:
程式碼:
補丁和註冊機程式碼就不發作者了,古得白
最不喜歡的就是寫破解教程,酒後一時衝動,老夫卿發少年狂,許下將寫一篇linux平臺逆向的文章的諾言,作此文實非頗不得已。
在此申明:本文在技術上非常初級,並沒有用到什麼高深的技術,本人水平亦有限,如有差錯,還請見諒!
開始之前的準備
正如C語言教程從 hello world 開始,我們也由一個 crackme 說開去。本文的例子程式你可以到這來下載:
http://www.crackmes.de/users/veneta/crackmes/linux_crackme_v2 。古人云“工欲善其事,必先利其器”,本文中所用到的工具及操作平臺羅列如下:
操作平臺: gentoo 2004.3 # kernel 2.6.9
逆向工具:
反彙編 -- objdump (這個工具基本上每個LINUX上都有)、lida( http://lida.sourceforge.net/ )
偵錯程式 -- gdb
十六進位制編輯器 -- hexedit
文字編輯器 -- vim
壓縮工具 -- upx (http://upx.sourceforge.net)
計算器 -- gcalctool(gnome計算器)
開始逆向之旅
首先我們看看程式基本資訊:
開啟控制檯,切換到程式所在目錄。執行“ objdump -x cm2 ”,顯示如下:
程式碼:
[[email protected]]$ objdump -x cm2 cm2: file format elf32-i386 cm2 architecture: i386, flags 0x00000102: EXEC_P, D_PAGED start address 0x08048080 程式頭: LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x000005b8 memsz 0x000005b8 flags r-x LOAD off 0x000005b8 vaddr 0x080495b8 paddr 0x080495b8 align 2**12 filesz 0x0000002c memsz 0x0000002c flags rw- Sections: Idx Name Size VMA LMA File off Algn SYMBOL TABLE: no symbols
我們可以看到start address是0x08048080,但有一個問題是Sections下面卻什麼都沒有。這不是一個正常的程式?
接下來,使用十六進位制工具 hexedit 檢視程式資訊。執行命令:hexedit cm2 ,顯示如下:
程式碼:
00000000 7F 45 4C 46 01 01 01 00 4C 69 6E 75 78 00 00 00 .ELF....Linux... 00000010 02 00 03 00 01 00 00 00 80 80 04 08 34 00 00 00 ............4... 00000020 00 00 00 00 00 00 00 00 34 00 20 00 02 00 00 00 ........4. ..... 00000030 00 00 00 00 01 00 00 00 00 00 00 00 00 80 04 08 ................ 00000040 00 80 04 08 B8 05 00 00 B8 05 00 00 05 00 00 00 ................ 00000050 00 10 00 00 01 00 00 00 B8 05 00 00 B8 95 04 08 ................ 00000060 B8 95 04 08 2C 00 00 00 2C 00 00 00 06 00 00 00 ....,...,....... 00000070 00 10 00 00 77 6C EA 93 7F 55 50 58 E4 05 0B 0A ....wl...UPX.... 00000080 31 ED 58 89 E1 8D 54 81 04 50 83 E4 F8 52 51 E8 1.X...T..P...RQ. 00000090 FE 01 00 00 F4 0A 00 24 49 6E 66 6F 3A 20 54 68 .......$Info: Th 000000A0 69 73 20 66 69 6C 65 20 69 73 20 70 61 63 6B 65 is file is packe 000000B0 64 20 77 69 74 68 20 74 68 65 20 55 50 58 20 65 d with the UPX e 000000C0 78 65 63 75 74 61 62 6C 65 20 70 61 63 6B 65 72 xecutable packer 000000D0 20 68 74 74 70 3A 2F 2F 75 70 78 2E 73 66 2E 6E http://upx.sf.n 000000E0 65 74 20 24 0A 00 24 49 64 3A 20 55 50 58 20 31 et $..$Id: UPX 1 000000F0 2E 32 34 20 43 6F 70 79 72 69 67 68 74 20 28 43 .24 Copyright (C 00000100 29 20 31 39 39 36 2D 32 30 30 32 20 74 68 65 20 ) 1996-2002 the 00000110 55 50 58 20 54 65 61 6D 2E 20 41 6C 6C 20 52 69 UPX Team. All Ri 00000120 67 68 74 73 20 52 65 73 65 72 76 65 64 2E 20 24 ghts Reserved.從上面的資訊中可以看到程式被UPX壓縮了,接下來請確信你係統中已有UPX,如果沒有請到上面給出的程式連結中下載。$
執行命令“ upx -d cm2 ”把程式解壓縮,顯示如下:
程式碼:
[[email protected] crack]$ upx -d cm2 Ultimate Packer for eXecutables Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 UPX 1.25 Markus F.X.J. Oberhumer & Laszlo Molnar Jun 29th 2004 File size Ratio Format Name -------------------- ------ ----------- ----------- 10584 <- 4870 46.01% linux/386 cm2 Unpacked 1 file.接下來,我們再使用命令“ objdump -x cm2 ”來檢視程式資訊。如下:
程式碼:
[[email protected] crack]$ objdump -x cm2 cm2: file format elf32-i386 cm2 architecture: i386, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x080488b0 程式頭: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000c0 memsz 0x000000c0 flags r-x INTERP off 0x000000f4 vaddr 0x080480f4 paddr 0x080480f4 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x0000109c memsz 0x0000109c flags r-x LOAD off 0x00002000 vaddr 0x0804a000 paddr 0x0804a000 align 2**12 filesz 0x00000398 memsz 0x00000ff0 flags rw- DYNAMIC off 0x00002248 vaddr 0x0804a248 paddr 0x0804a248 align 2**2 filesz 0x000000e0 memsz 0x000000e0 flags rw- NOTE off 0x00000108 vaddr 0x08048108 paddr 0x08048108 align 2**2 filesz 0x00000020 memsz 0x00000020 flags r-- 動態節: NEEDED libgtk-1.2.so.0 NEEDED libgdk-1.2.so.0 NEEDED libglib-1.2.so.0 NEEDED libc.so.6 INIT 0x8048758 FINI 0x8049074 HASH 0x8048128 STRTAB 0x804841c SYMTAB 0x80481fc STRSZ 0x225 SYMENT 0x10 DEBUG 0x0 PLTGOT 0x804a33c PLTRELSZ 0x98 PLTREL 0x11 JMPREL 0x80486c0 REL 0x80486b8 RELSZ 0x8 RELENT 0x8 VERNEED 0x8048688 VERNEEDNUM 0x1 VERSYM 0x8048642 版本引用: required from libc.so.6: 0x0d696911 0x00 03 GLIBC_2.1 0x0d696910 0x00 02 GLIBC_2.0 Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 080480f4 080480f4 000000f4 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .note.ABI-tag 00000020 08048108 08048108 00000108 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .hash 000000d4 08048128 08048128 00000128 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .dynsym 00000220 080481fc 080481fc 000001fc 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .dynstr 00000225 0804841c 0804841c 0000041c 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .gnu.version 00000044 08048642 08048642 00000642 2**1 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .gnu.version_r 00000030 08048688 08048688 00000688 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .rel.dyn 00000008 080486b8 080486b8 000006b8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 8 .rel.plt 00000098 080486c0 080486c0 000006c0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .init 00000017 08048758 08048758 00000758 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 10 .plt 00000140 08048770 08048770 00000770 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 11 .text 000007c4 080488b0 080488b0 000008b0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 12 .fini 0000001b 08049074 08049074 00001074 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 13 .rodata 00000008 08049090 08049090 00001090 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 14 .eh_frame 00000004 08049098 08049098 00001098 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 15 .data 00000248 0804a000 0804a000 00002000 2**2 CONTENTS, ALLOC, LOAD, DATA 16 .dynamic 000000e0 0804a248 0804a248 00002248 2**2 CONTENTS, ALLOC, LOAD, DATA 17 .ctors 00000008 0804a328 0804a328 00002328 2**2 CONTENTS, ALLOC, LOAD, DATA 18 .dtors 00000008 0804a330 0804a330 00002330 2**2 CONTENTS, ALLOC, LOAD, DATA 19 .jcr 00000004 0804a338 0804a338 00002338 2**2 CONTENTS, ALLOC, LOAD, DATA 20 .got 0000005c 0804a33c 0804a33c 0000233c 2**2 CONTENTS, ALLOC, LOAD, DATA 21 .bss 00000c58 0804a398 0804a398 00002398 2**2 ALLOC 22 .comment 00000119 00000000 00000000 00002398 2**0 CONTENTS, READONLY SYMBOL TABLE: no symbols從上面的資訊中可以看出,程式使用gtk編寫,程式入口start address=0x080488b0。
我們再進一步的檢視程式資訊,執行命令“objdump -T cm2 >iat.txt”,下面的資訊將會儲存到iat.txt檔案中。
程式碼:
[[email protected] crack]$ objdump -T cm2 cm2: file format elf32-i386 DYNAMIC SYMBOL TABLE: 00000000 DF *UND* 0000013d gtk_widget_show 0804a248 g DO *ABS* 00000000 Base _DYNAMIC 08048780 DF *UND* 000000e4 gtk_widget_show_all 00000000 DF *UND* 00000027 gtk_dialog_new 08048790 DF *UND* 000001db gtk_container_add 08048758 g DF .init 00000000 Base _init 080487a0 DF *UND* 000000d1 gtk_window_set_default_size 080487b0 DF *UND* 00000056 gtk_label_new 080487c0 DF *UND* 00000085 gtk_window_new 080487d0 DF *UND* 00000213 gtk_widget_set_uposition 080487e0 DF *UND* 0000010d gtk_window_set_title 080487f0 DF *UND* 0000010c gtk_entry_get_text 08048800 DF *UND* 00000242 gtk_box_pack_start 08048810 DF *UND* 00000067 gtk_init 08048820 DF *UND* 0000010d g_print 08048830 DF *UND* 0000007c gtk_main_quit 08048840 DF *UND* 000001d3 gtk_main 0804a398 g D *ABS* 00000000 Base __bss_start 08048850 DF *UND* 000000e0 GLIBC_2.0 __libc_start_main 08049074 g DF .fini 00000000 Base _fini 08048860 DF *UND* 000000c7 GLIBC_2.0 exit 0804a398 g D *ABS* 00000000 Base _edata 0804a33c g DO *ABS* 00000000 Base _GLOBAL_OFFSET_TABLE_ 0804aff0 g D *ABS* 00000000 Base _end 00000000 DF *UND* 00000028 GLIBC_2.1 fopen 08049094 g DO .rodata 00000004 Base _IO_stdin_used 00000000 DF *UND* 0000012e GLIBC_2.0 fwrite 08048870 DF *UND* 00000027 gtk_entry_new 00000000 w D *UND* 00000000 _Jv_RegisterClasses 08048880 DF *UND* 00000157 gtk_signal_connect 08048890 DF *UND* 0000006d gtk_button_new_with_label 080488a0 DF *UND* 00000044 gtk_vbox_new 00000000 w D *UND* 00000000 __gmon_start__我們再一次執行命令“objdump -d cm2 >disasm.txt”,對程式進行反彙編,並把結果儲存到disasm.txt中。
接下來,用VI開啟disasm.txt檔案。顯示如下:
相對WINDOW平臺的反彙編器,objdump 的反彙編結果在沒有除錯符號的情況下,不顯示API的名字。下一步API呼叫手工的加上。
我們開啟iat.txt檔案,把disasm.txt檔案中的地址全部轉換成函式名,例如:
程式碼:
8048979: 68 00 00 00 00 push $0x0 804897e: 68 03 00 00 00 push $0x3 8048983: e8 88 fe ff ff call 0x8048810轉換成
這樣將好看多了。這一點你可以寫個指令碼自動完成,而不用手工一個一個的替換。或者你也可以使用更強大的反彙編工器lida來自動顯示API呼叫名。為了方便初學者,下面使用LIDA來作為反彙編工具。用lida 載入程式,如下圖:
好了,前期的工作都做了。下面讓我們來執行一下程式,看看有沒有什麼值得參考的。執行後,出現一個視窗。如下:
如圖,提示我們的CRACK任務之一就是NOP掉這個視窗。點選關閉按鈕,出現第二個視窗,如下圖
這是註冊的主視窗。
對照LIDA中的反彙編程式碼加上GTK的一些基本知識,我們可以知道程式執行過程是這樣的:main->跳出killme視窗->註冊destroy事件處理函式->在關閉 killme 視窗時將引發destroy事件->執行回撥處理函式0x80489bd->跳出crackme視窗。
我們CRACK的任務就是nop掉killme視窗,以及找出註冊碼。
注:GTK的相關文件你可以到這來獲取 http://www.gtk.org/tutorial/
第一個任務:去除killme視窗。
用lida反彙編cm2,點選選單 view -> Functions 找到main函式,點選進入,如下所示:
程式碼:
main(): 08048970 55 push ebp 08048971 89 E5 mov ebp, esp 08048973 81 EC 08 00 00 00 sub esp, 0x8 08048979 68 00 00 00 00 push 0x0 0804897E 68 03 00 00 00 push 0x3 08048983 E8 88 FE FF FF call gtk_init (08048810) ; (near - 0x178) 08048988 90 nop -\ 08048989 90 nop \ 0804898A 90 nop |->怎麼會有nop指令出現? 0804898B 90 nop / 我們在這加入call Function___080489BD 0804898C 90 nop -/ 直接顯示crackme視窗,跳過killme視窗的呼叫。因為在 0804898D BE D2 A0 04 08 mov esi, " Kill this window (p" (0804A0D2) 08048992 E8 5C 04 00 00 call Function___08048DF3 (08048DF3) ; 建立killme視窗 08048997 68 00 00 00 00 push 0x0 0804899C 68 BD 89 04 08 push Function___080489BD (80489BD) ; 回撥函式,顯示crackme視窗 080489A1 68 28 A2 04 08 push "destroy" (0804A228) 080489A6 FF 35 A0 A3 04 08 push 0804A3A0 080489AC E8 CF FE FF FF call gtk_signal_connect (08048880) ; 建立destroy事件回撥函式0x080489BD 080489B1 81 C4 10 00 00 00 add esp, 0x10 080489B7 E8 84 FE FF FF call gtk_main (08048840) ; 顯示killme視窗 080489BC C3 ret我們跟入Function___08048DF3函式,如下:
程式碼:
Function___08048DF3: 08048DF3 55 push ebp ; xref ( 08048992 08048C9A 08048CA6 08048DAC ) 08048DF4 89 E5 mov ebp, esp 08048DF6 81 EC 08 00 00 00 sub esp, 0x8 08048DFC 68 01 00 00 00 push 0x1 08048E01 E8 BA F9 FF FF call gtk_window_new (080487C0) ; (near - 0x646) 08048E06 A3 A0 A3 04 08 mov 0x0804A3A0, eax 08048E0B 68 2C A0 04 08 push "CrackMe v13 (2 linux" (0804A02C) 08048E10 FF 35 A0 A3 04 08 push 0804A3A0 08048E16 E8 C5 F9 FF FF call gtk_window_set_title (080487E0) ; (near - 0x63B) 08048E1B 56 push esi 08048E1C E8 8F F9 FF FF call gtk_label_new (080487B0) ; (near - 0x671) 08048E21 50 push eax 08048E22 FF 35 A0 A3 04 08 push 0804A3A0 08048E28 E8 63 F9 FF FF call gtk_container_add (08048790) ; (near - 0x69D) 08048E2D 68 64 00 00 00 push 0x64 08048E32 68 2C 01 00 00 push 0x12C 08048E37 FF 35 A0 A3 04 08 push 0804A3A0 08048E3D E8 5E F9 FF FF call gtk_window_set_default_size (080487A0) ; (near - 0x6A2) 08048E42 FF 35 A0 A3 04 08 push 0804A3A0 08048E48 E8 33 F9 FF FF call gtk_widget_show_all (08048780) ; (near - 0x6CD) 08048E4D C9 leave 08048E4E C3 ret上面這個函式建立killme視窗。
為了去除這個killme視窗。我們可以在 程式碼:
08048988 90 nop -\ 08048989 90 nop \ 0804898A 90 nop |->怎麼會有nop指令出現? 0804898B 90 nop / 我們在這加入call Function___080489BD 0804898C 90 nop -/ 直接顯示crackme視窗,跳過killme視窗的呼叫。 0804898D BE D2 A0 04 08 mov esi, " Kill this window (p" (0804A0D2) 08048992 E8 5C 04 00 00 call Function___08048DF3 (08048DF3)上面的nop正好5個,我懷疑作者寫crackme在這有一個對crackme函式的呼叫,生成程式後,他手工把這個程式碼NOP掉了,他是故意留出空間來做提示。因為在crackme 視窗函式中有完整的視窗初始化和退出處理,如下:
程式碼:
08048C22 68 3D A2 04 08 push "clicked" (0804A23D)
08048C27 FF 35 AC A3 04 08 push 0804A3AC
08048C2D E8 4E FC FF FF call gtk_signal_connect (08048880) ; (near - 0x3B2)
08048C32 81 C4 10 00 00 00 add esp, 0x10
08048C38 E8 03 FC FF FF call gtk_main (08048840) ; (near - 0x3FD)
08048C3D 68 2C A0 04 08 push "CrackMe v13 (2 linux" (0804A02C)
08048C42 E8 D9 FB FF FF call g_print (08048820) ; (near - 0x427)
08048C47 81 C4 04 00 00 00 add esp, 0x4
08048C4D 68 00 00 00 00 push 0x0
08048C52 E8 09 FC FF FF call exit (08048860) ; 當點選crackme視窗上的quit按鈕後程序直接退出
Function___08048C57:
08048C57 55 push ebp
08048C58 89 E5 mov ebp, esp
08048C5A 81 EC 08 00 00 00 sub esp, 0x8
08048C60 E8 17 00 00 00 call Function___08048C7C (08048C7C) ; (near + 0x17)
08048C65 B8 00 00 00 00 mov eax, 0x0
08048C6A C9 leave
08048C6B C3 ret
從上面的程式碼可以看到,如果先呼叫crackme 視窗的函式,那麼 killme 視窗就不會出現了。好的,下面我們就改08048988處的指令為 call 080489BD ,用計算器算一下:80489BD-08048988-5=00000030,得到程式碼為 e8 30 00 00 00 。嘿嘿!
好的,用hexedit 開啟 cm2 程式。看看前面objdump -x cm2列出的基地址為0x8048000,所以對應的file offset應該是0x8048988-0x8048000=0x988,我們按 return 鍵,開啟 go to 視窗,輸入 0x988 ,定位到08048988處,改程式碼為e830000000。改完後,“ ./cm2 ”執行程式,OK。出現 crackme 視窗了。
第二個任務,找出正確的註冊碼。
為保持本文一個苗條的身材及加大本文所包含的資訊量,我就不講怎麼根據按鈕名找對應的點選事件處理函數了,講一種簡單省事的方法,找註冊碼最省事的方法當然是動態跟蹤啦。搞不好還可以看到明碼喲。費話不多說,執行命令: gdb cm2 。提示沒有符號檔案,不用管它。
下斷點:
程式碼:
br gtk_entry_get_text 注(類似於WIN平臺下的 getdlgitemtexta )再鍵入命令 “ run ”執行程式。出現了介面。
輸入名字和註冊碼,我這用的是:
名字:ncc2008
註冊碼:78787878
按crackme按鈕,中斷到gdb中。
程式碼:
Breakpoint 1, 0x40096eb0 in gtk_entry_get_text () from /usr/lib/libgtk-1.2.so.0讓我們看看是哪個CALL呼叫的,下命令"info frame",顯示如下:
程式碼:
(gdb) info frame Stack level 0, frame at 0xbfffe250: eip = 0x40096eb0 in gtk_entry_get_text; saved eip 0x8048cc1 ;從這CALL來的 called by frame at 0xbfffe254 Arglist at 0xbfffe248, args: Locals at 0xbfffe248, Previous frame's sp is 0xbfffe250 Saved registers: eip at 0xbfffe24c呵呵,清除全部斷點,下命令“d”。在0x8048cc1下一個斷點:
程式碼:
br *0x8048cc1,然後鍵“C”繼續執行程式。
程式中斷到我們所下的斷點0x8048cc1處。讓我們看看彙編程式碼:
下命令:x /10i $eip
顯示如下:
程式碼:
(gdb) x /10i $eip 0x8048cc1: mov %eax,%edx 0x8048cc3: call 0x8048fc5 0x8048cc8: cmp $0x20,%eax 0x8048ccd: jne 0x8048ca1 0x8048ccf: mov %edx,0x804a3e8 0x8048cd5: call 0x8048f50 0x8048cda: pushl 0x804a3c0 0x8048ce0: call 0x80487f0 0x8048ce5: mov %eax,%edx 0x8048ce7: call 0x8048fc5看不懂?我們再看lida 中的 0x8048cc1處的程式碼。
程式碼:
Function___08048CAD: 08048CAD 55 push ebp 08048CAE 89 E5 mov ebp, esp 08048CB0 81 EC 08 00 00 00 sub esp, 0x8 08048CB6 FF 35 C4 A3 04 08 push 0804A3C4 08048CBC E8 2F FB FF FF call gtk_entry_get_text (080487F0) ; (near - 0x4D1) 08048CC1 89 C2 mov edx, eax 08048CC3 E8 FD 02 00 00 call Function___08048FC5 (08048FC5) ; 註冊碼長 08048CC8 3D 20 00 00 00 cmp eax, 0x20 08048CCD 75 D2 jnz Label_08048CA1 (08048CA1) ; 註冊碼必需是32個字元 08048CCF 89 15 E8 A3 04 08 mov 0804A3E8, edx 08048CD5 E8 76 02 00 00 call Function___08048F50 (08048F50) ; a2i,字串到 hex轉換 08048CDA FF 35 C0 A3 04 08 push 0804A3C0 08048CE0 E8 0B FB FF FF call gtk_entry_get_text (080487F0) ; (near - 0x4F5) 08048CE5 89 C2 mov edx, eax 08048CE7 E8 D9 02 00 00 call Function___08048FC5 (08048FC5) ; (near + 0x2D9) 08048CEC BE F0 A7 04 08 mov esi, 0x804A7F0 08048CF1 50 push eax 08048CF2 3D 03 00 00 00 cmp eax, 0x3 08048CF7 72 A8 jc Label_08048CA1 (08048CA1) ; 使用者名稱必需大於3個字元 08048CF9 89 C1 mov ecx, eax 08048CFB 8A 02 mov al, [edx] ; xref ( 08048D01 ) 08048CFD 88 06 mov [esi], al 08048CFF 42 inc edx 08048D00 46 inc esi 08048D01 E2 F8 loop 08048CFB ; (near 0xF8) 08048D03 C7 05 C8 A3 04 08 10 A2 04 08 mov 0804A3C8, "MBECrew" (0804A210) 08048D0D C7 05 CC A3 04 08 07 00 00 00 mov 0804A3CC, 0x7 08048D17 E8 33 01 00 00 call Function___08048E4F (08048E4F) ; (near + 0x133) 08048D1C C7 05 D0 A3 04 08 F0 A3 04 08 mov 0804A3D0, 0x804A3F0 08048D26 C7 05 D4 A3 04 08 10 00 00 00 mov 0804A3D4, 0x10 08048D30 E8 87 01 00 00 call Function___08048EBC (08048EBC) ; 註冊碼每位元組與F0相異或 08048D35 C7 05 C8 A3 04 08 10 A2 04 08 mov 0804A3C8, "MBECrew" (0804A210) 08048D3F C7 05 CC A3 04 08 07 00 00 00 mov 0804A3CC, 0x7 08048D49 E8 01 01 00 00 call Function___08048E4F (08048E4F) ; (near + 0x101) 08048D4E 58 pop eax 08048D4F C7 05 D0 A3 04 08 F0 A7 04 08 mov 0804A3D0, 0x804A7F0 08048D59 A3 D4 A3 04 08 mov 0x0804A3D4, eax 08048D5E E8 59 01 00 00 call Function___08048EBC (08048EBC) ; (near + 0x159) 08048D63 BE F0 A3 04 08 mov esi, 0x804A3F0 08048D68 BA F0 A7 04 08 mov edx, 0x804A7F0 08048D6D B9 10 00 00 00 mov ecx, 0x10 Label_08048D72: 08048D72 8A 02 mov al, [edx] ; xref ( 08048D7C 08048DB8 ) 08048D74 3C 00 cmp al, 0x0 08048D76 74 3B jz Label_08048DB3 (08048DB3) ; (near + 0x3B) 08048D78 04 0A add al, 0xA 08048D7A 30 06 xor [esi], al 08048D7C E2 F4 loop Label_08048D72 (08048D72) ; (near 0xF4) 08048D7E BA 18 A2 04 08 mov edx, 0x804A218 08048D83 BE F0 A3 04 08 mov esi, 0x804A3F0 08048D88 B9 04 00 00 00 mov ecx, 0x4 08048D8D 8B 02 mov eax, [edx] ; xref ( 08048DA5 ) 08048D8F 33 06 xor eax, [esi] ; 下斷點在這 08048D91 85 C0 test eax, eax 08048D93 0F 85 08 FF FF FF jnz Label_08048CA1 (08048CA1) ; 跳就死定了 08048D99 81 C2 04 00 00 00 add edx, 0x4 08048D9F 81 C6 04 00 00 00 add esi, 0x4 08048DA5 E2 E6 loop 08048D8D ; (near 0xE6) 08048DA7 BE 8F A0 04 08 mov esi, " cracked ohh yeah !!" (0804A08F) 08048DAC E8 42 00 00 00 call Function___08048DF3 (08048DF3) ; (near + 0x42) 08048DB1 C9 leave 08048DB2 C3 ret Label_08048DB3: 08048DB3 BA F0 A7 04 08 mov edx, 0x804A7F0 ; xref ( 08048D76 ) 08048DB8 EB B8 jmp Label_08048D72 (08048D72) ; (near 0xB8)
接下來,我們就一步一步跟吧!整個過程單調無趣,不多說了。註冊碼必需是32位,我使用“12345678abcdef0123456789abcdef0”
跟蹤其流程:
轉換註冊碼“12345678abcdef0123456789abcdef0”為:
程式碼:
0x804a3f0: 0x12 0x34 0x56 0x78 0x9a 0xbc 0xde 0xf0 0x804a3f8: 0x12 0x34 0x56 0x78 0x9a 0xbc 0xde 0xf0然後每一位元組與"0xf0"相異或,生成:
程式碼:
0x804a3f0: 0xe2 0xc4 0xa6 0x88 0x6a 0x4c 0x2e 0x00 0x804a3f8: 0xe2 0xc4 0xa6 0x88 0x6a 0x4c 0x2e 0x00我們在08048D8F下個斷點,中斷後可以看到正確的值,edx中的值為:
程式碼:
(gdb) x /20xb $edx 0x804a218: 0xc4 0x84 0x0b 0xb5 0xa1 0x02 0x0d 0x97 0x804a220: 0x5c 0xb2 0xe1 0xc9 0xa4 0x91 0x52 0xcc0x804a218處的值與0x804a3f0處的值相比較,相等就註冊成功。結合前面註冊碼的變換,可以把上面的每位元組與F0異或就是正確的註冊碼了,掏出計算器,計算如下:
程式碼:
3474fb4551f2fd67ac4211395461a23c註冊碼與名字無關,名字可隨便寫,在程式中輸入上面的註冊碼,成功!
補丁和註冊機程式碼就不發作者了,古得白