程序破解
NOP天吓、JNE贿肩、JE、JMP龄寞、CMP匯編指令的機(jī)器碼
NOP:NOP指令即“空指令”汰规。執(zhí)行到NOP指令時(shí),CPU什么也不做物邑,僅僅當(dāng)做一個(gè)指令執(zhí)行過去并繼續(xù)執(zhí)行NOP后面的一條指令溜哮。(機(jī)器碼:90)
JNE:條件轉(zhuǎn)移指令,如果不相等則跳轉(zhuǎn)色解。(機(jī)器碼:75)
JE:條件轉(zhuǎn)移指令茂嗓,如果相等則跳轉(zhuǎn)。(機(jī)器碼:74)
JMP:無條件轉(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)指令通過識(shí)別這些被影響的標(biāo)志寄存器位來得知比較結(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í)行文件另其無論輸入什么密碼的是正確的疙剑。
修改思路:將jne 跳轉(zhuǎn)偏移量改為0先煎,這樣40063a位置的指令就相當(dāng)于繼續(xù)執(zhí)行輸出right。
實(shí)現(xiàn)方法:
輸入指令:
vim login
打開可執(zhí)行文件
輸入:
%!xxd
進(jìn)入十六進(jìn)制編輯模式茅逮,如下圖所示:
然后輸入
/750c
找到j(luò)ne指令的位置璃赡,如下圖所示:
將750c改成7500表示跳轉(zhuǎn)到下一條指令繼續(xù)執(zhí)行,相當(dāng)于NOP氮唯。
輸入
%!xxd -r
切換回原模式
輸入
wq
保存后退出鉴吹。
運(yùn)行修改后的文件效果如下:
由圖可見無論輸入什么密碼都是正確的,修改成功惩琉。
如果想輸入什么密碼都是錯(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文件頭串纺,在文件的開始,保存了路線圖椰棘,描述了該文件的組織情況纺棺。
program header table :程序文件頭表,告訴系統(tǒng)如何創(chuàng)建進(jìn)程映像邪狞。用來構(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)文件可以有,也可以沒有這個(gè)表癣疟。
具體分析見ELF文件格式分析挣柬。
ELF文件格式分析
ELF全稱Executable and Linkable Format,可執(zhí)行連接格式,ELF格式的文件用于存儲(chǔ)Linux程序睛挚。ELF文件(目標(biāo)文件)格式主要三種:
1)可重定向文件:文件保存著代碼和適當(dāng)?shù)臄?shù)據(jù)邪蛔,用來和其他的目標(biāo)文件一起來創(chuàng)建一個(gè)可執(zhí)行文件或者是一個(gè)共享目標(biāo)文件。(目標(biāo)文件或者靜態(tài)庫文件扎狱,即linux通常后綴為.a和.o的文件)
2)可執(zhí)行文件:文件保存著一個(gè)用來執(zhí)行的程序侧到。(例如bash,gcc等)
3)共享目標(biāo)文件:共享庫淤击。文件保存著代碼和合適的數(shù)據(jù)匠抗,用來被下連接編輯器和動(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;
取一段簡單的代碼進(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ì)象矢腻。接下來02字節(jié)表示是一個(gè)64位對(duì)象,接下來01字節(jié)表示是小端法表示射赛,再接下來的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,表示程序頭部表的起始位置在磁盤文件中的偏移量為64字節(jié)豁生。e_shoff的值為0x19d8,表示節(jié)頭部表(Section Header Table)的起始位置在磁盤文件中的偏移量為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)的索引。
通過文件頭找到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)開始的Section Header Table的數(shù)據(jù)結(jié)構(gòu)如Elf64_Shdr結(jié)構(gòu)體所示。
通過輸入命令
readelf -S hello
可以查看Section Header Table躁倒,如下圖所示:
通過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。
然后通過相對(duì)文件頭的偏移地址和節(jié)大小可以找到各section拉一。
理解常見.text .strtab .symtab .rodata的section采盒。
1.text section是可執(zhí)行指令的集合,.data和.text都是屬于PROGBITS類型的section蔚润,這是將來要運(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)锌杀。