程序破解
NOP、JNE、JE、JMP、CMP匯編指令的機(jī)器碼
NOP:NOP指令即“空指令”。執(zhí)行到NOP指令時(shí),CPU什么也不做,僅僅當(dāng)做一個(gè)指令執(zhí)行過(guò)去并繼續(xù)執(zhí)行NOP后面的一條指令。(機(jī)器碼:90)
JNE:條件轉(zhuǎn)移指令,如果不相等則跳轉(zhuǎn)。(機(jī)器碼:75)
JE:條件轉(zhuǎn)移指令,如果相等則跳轉(zhuǎn)。(機(jī)器碼:74)
JMP:無(wú)條件轉(zhuǎn)移指令。段內(nèi)直接短轉(zhuǎn)Jmp short(機(jī)器碼:EB)段內(nèi)直接近轉(zhuǎn)移Jmp near(機(jī)器碼:E9)段內(nèi)間接轉(zhuǎn)移Jmp word(機(jī)器碼:FF)段間直接(遠(yuǎn))轉(zhuǎn)移Jmp far(機(jī)器碼:EA)
CMP:比較指令,功能相當(dāng)于減法指令,只是對(duì)操作數(shù)之間運(yùn)算比較,不保存結(jié)果。cmp指令執(zhí)行后,將對(duì)標(biāo)志寄存器產(chǎn)生影響。其他相關(guān)指令通過(guò)識(shí)別這些被影響的標(biāo)志寄存器位來(lái)得知比較結(jié)果。
反匯編與十六進(jìn)制編程器
實(shí)驗(yàn)源碼:
login.c
#include<stdio.h>
void main()
{
int pass=123;
int enter;
printf("please enter the password:\n");
scanf("%d",&enter);
if(enter==pass)
printf("right\n");
else
printf("wrong\n");
}
運(yùn)行效果如下:
輸入命令:
objdump -d login
查看main函數(shù)
現(xiàn)在的需求是:修改可執(zhí)行文件另其無(wú)論輸入什么密碼的是正確的。
修改思路:將jne 跳轉(zhuǎn)偏移量改為0,這樣40063a位置的指令就相當(dāng)于繼續(xù)執(zhí)行輸出right。
實(shí)現(xiàn)方法:
輸入指令:
vim login
打開(kāi)可執(zhí)行文件
輸入:
%!xxd
進(jìn)入十六進(jìn)制編輯模式,如下圖所示:
然后輸入
/750c
找到j(luò)ne指令的位置,如下圖所示:
將750c改成7500表示跳轉(zhuǎn)到下一條指令繼續(xù)執(zhí)行,相當(dāng)于NOP。
輸入
%!xxd -r
切換回原模式
輸入
wq
保存后退出。
運(yùn)行修改后的文件效果如下:
由圖可見(jiàn)無(wú)論輸入什么密碼都是正確的,修改成功。
如果想輸入什么密碼都是錯(cuò)誤的,只需要將750c改為eb0c即可,eb為JMP,0c為輸出"wrong"的代碼相對(duì)偏移量。
效果如下:
如果想輸入原先正確的密碼為"wrong",輸出其他密碼為"right",只需把750c改為740c即可,74相當(dāng)于JE,相等則跳轉(zhuǎn)。
效果如下:
可執(zhí)行文件的基本格式
Linux可執(zhí)行文件格式為ELF即Executable and Linkable Format。
格式:
ELF header :ELF文件頭,在文件的開(kāi)始,保存了路線圖,描述了該文件的組織情況。
program header table :程序文件頭表,告訴系統(tǒng)如何創(chuàng)建進(jìn)程映像。用來(lái)構(gòu)造進(jìn)程映像的目標(biāo)文件必須具有程序頭部表,可重定位文件不需要這個(gè)表。
.text段:存儲(chǔ)只讀程序
.data段:存儲(chǔ)已經(jīng)初始化的全局變量和靜態(tài)變量
.bss段:存儲(chǔ)未初始化的全局變量和靜態(tài)變量,因?yàn)檫@些變量的值為0,所以這個(gè)段在文件當(dāng)中不占據(jù)空間
.rodata段:存儲(chǔ)只讀數(shù)據(jù),比如字符串常量
...(各種(節(jié)))
Section header table:節(jié)頭部表,包含了描述文件節(jié)區(qū)的信息,每個(gè)節(jié)區(qū)在表中都有一項(xiàng),每一項(xiàng)給出諸如節(jié)區(qū)名稱、節(jié)區(qū)大小這類信息。用于鏈接的目標(biāo)文件必須包含節(jié)區(qū)頭部表,其他目標(biāo)文件可以有,也可以沒(méi)有這個(gè)表。
具體分析見(jiàn)ELF文件格式分析。
ELF文件格式分析
ELF全稱Executable and Linkable Format,可執(zhí)行連接格式,ELF格式的文件用于存儲(chǔ)Linux程序。ELF文件(目標(biāo)文件)格式主要三種:
1)可重定向文件:文件保存著代碼和適當(dāng)?shù)臄?shù)據(jù),用來(lái)和其他的目標(biāo)文件一起來(lái)創(chuàng)建一個(gè)可執(zhí)行文件或者是一個(gè)共享目標(biāo)文件。(目標(biāo)文件或者靜態(tài)庫(kù)文件,即linux通常后綴為.a和.o的文件)
2)可執(zhí)行文件:文件保存著一個(gè)用來(lái)執(zhí)行的程序。(例如bash,gcc等)
3)共享目標(biāo)文件:共享庫(kù)。文件保存著代碼和合適的數(shù)據(jù),用來(lái)被下連接編輯器和動(dòng)態(tài)鏈接器鏈接。(linux下后綴為.so的文件。)

ELF文件頭
查看/usr/include/elf.h中的ELF頭文件數(shù)據(jù)結(jié)構(gòu)。
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
取一段簡(jiǎn)單的代碼進(jìn)行分析:
hello.c
#include<stdio.h>
void main()
{
printf("hello");
}
輸入指令
readelf -h hello
得到ELF文件頭信息:
由圖可看出ELF文件頭大小為64字節(jié)。
輸入命令:
hexdump -x hello -n 64
對(duì)ELF頭的16進(jìn)制表進(jìn)行分析:
第一行對(duì)應(yīng)e_ident[EI_NIDENT],實(shí)際內(nèi)容為:7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 ,前四個(gè)字節(jié)7f454c46(0x45,0x4c,0x46是'e','l','f'對(duì)應(yīng)的ascii編碼)是一個(gè)魔數(shù),表示這是一個(gè)ELF對(duì)象。接下來(lái)02字節(jié)表示是一個(gè)64位對(duì)象,接下來(lái)01字節(jié)表示是小端法表示,再接下來(lái)的01字節(jié)表示文件頭的版本。剩下的默認(rèn)設(shè)置為0。
第二行,e_type值為0x0002,表示是一個(gè)可執(zhí)行文件。e_machine的值為0x003e表示目標(biāo)文件所期待的系統(tǒng)架構(gòu)為Advanced Micro Devices X86-64。e_version值為0x00000001,表示是當(dāng)前版本。e_entry的值為0x00400430表示程序入口地址。
第三行,e_phoff的值為0x0040,表示程序頭部表的起始位置在磁盤(pán)文件中的偏移量為64字節(jié)。e_shoff的值為0x19d8,表示節(jié)頭部表(Section Header Table)的起始位置在磁盤(pán)文件中的偏移量為6616字節(jié)。
第四行,e_flags的值為e_flags值為0x00000000,表示未知處理器特定標(biāo)志。e_ehsize值為0x0040表示ELF文件頭部的大小為64字節(jié)。e_phentsize的值為0x0038,表示程序頭部表(Program Header Table)中每一個(gè)表項(xiàng)的大小56字節(jié)。e_shnum值為0x0009,表示程序頭部表(Program Header Table)中總共有9個(gè)表項(xiàng)。e_shentsize的值為0x0040,表示節(jié)頭部表(Section Header Table)中每一個(gè)表項(xiàng)的大小為64字節(jié)。e_shnum值為0x001f,表示節(jié)頭部表(Section Header Table)中總共有31個(gè)表項(xiàng)。e_shstrndx的值為:0x001c表示節(jié)頭部表(Section Header Table)中與節(jié)名字表相對(duì)應(yīng)的表項(xiàng)的索引。
通過(guò)文件頭找到section header table,理解其內(nèi)容
在/usr/include/elf.h中section header table的數(shù)據(jù)結(jié)構(gòu)定義如下:
typedef struct
{
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;
typedef struct
{
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
由上述分析可知節(jié)頭部表(Section Header Table)的起始位置文件頭的偏移量為0x19d8字節(jié)。
輸入命令:
xxd hello
找到0x19d8即Section Header Table的起始點(diǎn)如下圖所示:
從起始點(diǎn)開(kāi)始的Section Header Table的數(shù)據(jù)結(jié)構(gòu)如Elf64_Shdr結(jié)構(gòu)體所示。
通過(guò)輸入命令
readelf -S hello
可以查看Section Header Table,如下圖所示:

通過(guò)section header table找到各section
由前面的分析可知節(jié)頭部表(Section Header Table)中每一個(gè)表項(xiàng)的大小為64字節(jié)。
在第一節(jié)中,內(nèi)容全部為0不表示任何段。
在第二節(jié)中,為.interp段,段偏移sh_offset為0X238(紅線),段大小sh_size為0X1c(藍(lán)線)。
在第三節(jié)中,為.note.ABI-tag節(jié),節(jié)偏移sh_offset為0X 254(紅線),節(jié)大小sh_size為0X 20(藍(lán)線)。
第四個(gè)節(jié),為.note.gnu.build-i段,節(jié)偏移sh_offset為0X 274(紅線), 節(jié)大小sh_size為0X 24(藍(lán)線)。
第五個(gè)節(jié),為.gnu.hash節(jié),節(jié)偏移sh_offset為0X 298(紅線), 節(jié)大小sh_size為0X 1c(藍(lán)線)。
............中間節(jié)省略...........
第14節(jié).text節(jié)的表項(xiàng)起始地址=0x19d8+14*64=0x1d58
第14節(jié).text節(jié)的節(jié)偏移為0x430字節(jié),節(jié)大小為0x182字節(jié)。
其他節(jié)同理可推出,其他節(jié)起始地址的表項(xiàng)起始地址=0x19d8+節(jié)序號(hào)*64。
然后通過(guò)相對(duì)文件頭的偏移地址和節(jié)大小可以找到各section。
理解常見(jiàn).text .strtab .symtab .rodata的section。
1.text section是可執(zhí)行指令的集合,.data和.text都是屬于PROGBITS類型的section,這是將來(lái)要運(yùn)行的程序與代碼。
2.strtab section是屬于STRTAB類型的section,可以在文件中看到,它存著字符串,儲(chǔ)存著符號(hào)的名字。
3.symtab section存放所有section中定義的符號(hào)名字,比如“data_items”,“start_loop”。 .symtab section是屬于SYMTAB類型的section,它描述了.strtab中的符號(hào)在“內(nèi)存”中對(duì)應(yīng)的“內(nèi)存地址”。
4.rodata section,ro代表read only,即只讀數(shù)據(jù)(const)。