從今天開始我們正式開始Android的逆向之旅,關於逆向的相關知識,想必大家都不陌生了,逆向領域是一個充滿挑戰和神祕的領域。作爲一名Android開發者,每個人都想去探索這個領域,因爲一旦你破解了別人的內容,成就感肯定爆棚,不過相反的是,我們不僅要研究破解之道,也要研究加密之道,因爲加密和破解是相生相剋的。但是我們在破解的過程中可能最頭疼的是native層,也就是so文件的破解。所以我們先來詳細瞭解一下so文件的內容下面就來看看我們今天所要介紹的內容。今天我們先來介紹一下elf文件的格式,因爲我們知道android中的so文件就是elf文件,所以需要了解so文件,必須先來了解一下elf文件的格式,對於如何詳細瞭解一個elf文件,就是手動的寫一個工具類來解析一個elf文件。
第二、準備資料
我們需要了解elf文件的格式,關於elf文件格式詳解,網上已經有很多介紹資料了。這裏我也不做太多的解釋了。不過有兩個資料還是需要介紹一下的,因爲網上的內容真的很多,很雜。這兩個資料是最全的,也是最好的。我就是看這兩個資料來操作的:
第一個資料是非蟲大哥的經典之作:
看吧,是不是超級詳細?後面我們用Java代碼來解析elf文件的時候,就是按照這張圖來的。但是這張圖有些數據結構解釋的還不是很清楚,所以第二個資料來了。
第二個資料:北京大學實驗室出的標準版
http://download.csdn.net/detail/jiangwei0910410003/9204051
這裏就不對這個文件做詳細解釋了,後面在做解析工作的時候,會截圖說明。
關於上面的這兩個資料,這裏還是多數兩句:一定要仔細認真的閱讀。這個是經典之作。也是後面工作的基礎。
第三、工具
當然這裏還需要介紹一個工具,因爲這個工具在我們下面解析elf文件的時候,也非常有用,而且是檢查我們解析elf文件的模板。
就是很出名的:readelf命令
不過Window下這個命令不能用,因爲這個命令是Linux的,所以我們還得做個工作就是安裝Cygwin。關於這個工具的安裝,大家可以看看這篇文章:
http://blog.csdn.net/jiangwei0910410003/article/details/17710243
不過在下載的過程中,我擔心小朋友們會遇到挫折,所以很貼心的,放到的雲盤裏面:
下載下來之後,需要改一個東西才能用:
該一下這個文件:
這個路徑要改成你本地cygwin64中的bin目錄的路徑,不然運行錯誤的。改好之後,直接運行Cygwin.bat就可以了。
關於readelf工具我們這裏不做太詳細的介紹,只介紹我們要用到的命令:
1、readelf -h xxx.so
查看so文件的頭部信息
2、readelf -S xxx.so
查看so文件的段(Section)頭的信息
3、readelf -l xxx.so
查看so文件的程序段頭信息(Program)
4、readelf -a xxx.so
查看so文件的全部內容
還有很多命令用法,這裏就不在細說了,網上有很多介紹的~~
第四、實際操作解析Elf文件(Java代碼&C++代碼)
上面我們介紹了elf文件格式資料,elf文件的工具,那麼下面我們就來實際操作一下,來用Java代碼手把手的解析一個libhello-jni.so文件。關於這個libhello-jni.so文件的下載地址:
http://download.csdn.net/detail/jiangwei0910410003/9204087
1、首先定義elf文件中各個結構體內容
這個我們需要參考elf.h這個頭文件的格式了。這個文件網上也是有的,這裏還是給個下載鏈接吧:
http://download.csdn.net/detail/jiangwei0910410003/9204081
我們看看Java中定義的elf文件的數據結構類:
- package com.demo.parseso;
- import java.util.ArrayList;
- public class ElfType32 {
- public elf32_rel rel;
- public elf32_rela rela;
- public ArrayList<Elf32_Sym> symList = new ArrayList<Elf32_Sym>();
- public elf32_hdr hdr;//elf頭部信息
- public ArrayList<elf32_phdr> phdrList = new ArrayList<elf32_phdr>();//可能會有多個程序頭
- public ArrayList<elf32_shdr> shdrList = new ArrayList<elf32_shdr>();//可能會有多個段頭
- public ArrayList<elf32_strtb> strtbList = new ArrayList<elf32_strtb>();//可能會有多個字符串值
- public ElfType32() {
- rel = new elf32_rel();
- rela = new elf32_rela();
- hdr = new elf32_hdr();
- }
- /**
- * typedef struct elf32_rel {
- Elf32_Addr r_offset;
- Elf32_Word r_info;
- } Elf32_Rel;
- *
- */
- public class elf32_rel {
- public byte[] r_offset = new byte[4];
- public byte[] r_info = new byte[4];
- @Override
- public String toString(){
- return "r_offset:"+Utils.bytes2HexString(r_offset)+";r_info:"+Utils.bytes2HexString(r_info);
- }
- }
- /**
- * typedef struct elf32_rela{
- Elf32_Addr r_offset;
- Elf32_Word r_info;
- Elf32_Sword r_addend;
- } Elf32_Rela;
- */
- public class elf32_rela{
- public byte[] r_offset = new byte[4];
- public byte[] r_info = new byte[4];
- public byte[] r_addend = new byte[4];
- @Override
- public String toString(){
- return "r_offset:"+Utils.bytes2HexString(r_offset)+";r_info:"+Utils.bytes2HexString(r_info)+";r_addend:"+Utils.bytes2HexString(r_info);
- }
- }
- /**
- * typedef struct elf32_sym{
- Elf32_Word st_name;
- Elf32_Addr st_value;
- Elf32_Word st_size;
- unsigned char st_info;
- unsigned char st_other;
- Elf32_Half st_shndx;
- } Elf32_Sym;
- */
- public static class Elf32_Sym{
- public byte[] st_name = new byte[4];
- public byte[] st_value = new byte[4];
- public byte[] st_size = new byte[4];
- public byte st_info;
- public byte st_other;
- public byte[] st_shndx = new byte[2];
- @Override
- public String toString(){
- return "st_name:"+Utils.bytes2HexString(st_name)
- +"\nst_value:"+Utils.bytes2HexString(st_value)
- +"\nst_size:"+Utils.bytes2HexString(st_size)
- +"\nst_info:"+(st_info/16)
- +"\nst_other:"+(((short)st_other) & 0xF)
- +"\nst_shndx:"+Utils.bytes2HexString(st_shndx);
- }
- }
- public void printSymList(){
- for(int i=0;i<symList.size();i++){
- System.out.println();
- System.out.println("The "+(i+1)+" Symbol Table:");
- System.out.println(symList.get(i).toString());
- }
- }
- //Bind字段==》st_info
- public static final int STB_LOCAL = 0;
- public static final int STB_GLOBAL = 1;
- public static final int STB_WEAK = 2;
- //Type字段==》st_other
- public static final int STT_NOTYPE = 0;
- public static final int STT_OBJECT = 1;
- public static final int STT_FUNC = 2;
- public static final int STT_SECTION = 3;
- public static final int STT_FILE = 4;
- /**
- * 這裏需要注意的是還需要做一次轉化
- * #define ELF_ST_BIND(x) ((x) >> 4)
- #define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
- */
- /**
- * typedef struct elf32_hdr{
- unsigned char e_ident[EI_NIDENT];
- Elf32_Half e_type;
- Elf32_Half e_machine;
- Elf32_Word e_version;
- Elf32_Addr e_entry; // Entry point
- Elf32_Off e_phoff;
- Elf32_Off e_shoff;
- Elf32_Word e_flags;
- Elf32_Half e_ehsize;
- Elf32_Half e_phentsize;
- Elf32_Half e_phnum;
- Elf32_Half e_shentsize;
- Elf32_Half e_shnum;
- Elf32_Half e_shstrndx;
- } Elf32_Ehdr;
- */
- public class elf32_hdr{
- public byte[] e_ident = new byte[16];
- public byte[] e_type = new byte[2];
- public byte[] e_machine = new byte[2];
- public byte[] e_version = new byte[4];
- public byte[] e_entry = new byte[4];
- public byte[] e_phoff = new byte[4];
- public byte[] e_shoff = new byte[4];
- public byte[] e_flags = new byte[4];
- public byte[] e_ehsize = new byte[2];
- public byte[] e_phentsize = new byte[2];
- public byte[] e_phnum = new byte[2];
- public byte[] e_shentsize = new byte[2];
- public byte[] e_shnum = new byte[2];
- public byte[] e_shstrndx = new byte[2];
- @Override
- public String toString(){
- return "magic:"+ Utils.bytes2HexString(e_ident)
- +"\ne_type:"+Utils.bytes2HexString(e_type)
- +"\ne_machine:"+Utils.bytes2HexString(e_machine)
- +"\ne_version:"+Utils.bytes2HexString(e_version)
- +"\ne_entry:"+Utils.bytes2HexString(e_entry)
- +"\ne_phoff:"+Utils.bytes2HexString(e_phoff)
- +"\ne_shoff:"+Utils.bytes2HexString(e_shoff)
- +"\ne_flags:"+Utils.bytes2HexString(e_flags)
- +"\ne_ehsize:"+Utils.bytes2HexString(e_ehsize)
- +"\ne_phentsize:"+Utils.bytes2HexString(e_phentsize)
- +"\ne_phnum:"+Utils.bytes2HexString(e_phnum)
- +"\ne_shentsize:"+Utils.bytes2HexString(e_shentsize)
- +"\ne_shnum:"+Utils.bytes2HexString(e_shnum)
- +"\ne_shstrndx:"+Utils.bytes2HexString(e_shstrndx);
- }
- }
- /**
- * typedef struct elf32_phdr{
- Elf32_Word p_type;
- Elf32_Off p_offset;
- Elf32_Addr p_vaddr;
- Elf32_Addr p_paddr;
- Elf32_Word p_filesz;
- Elf32_Word p_memsz;
- Elf32_Word p_flags;
- Elf32_Word p_align;
- } Elf32_Phdr;
- */
- public static class elf32_phdr{
- public byte[] p_type = new byte[4];
- public byte[] p_offset = new byte[4];
- public byte[] p_vaddr = new byte[4];
- public byte[] p_paddr = new byte[4];
- public byte[] p_filesz = new byte[4];
- public byte[] p_memsz = new byte[4];
- public byte[] p_flags = new byte[4];
- public byte[] p_align = new byte[4];
- @Override
- public String toString(){
- return "p_type:"+ Utils.bytes2HexString(p_type)
- +"\np_offset:"+Utils.bytes2HexString(p_offset)
- +"\np_vaddr:"+Utils.bytes2HexString(p_vaddr)
- +"\np_paddr:"+Utils.bytes2HexString(p_paddr)
- +"\np_filesz:"+Utils.bytes2HexString(p_filesz)
- +"\np_memsz:"+Utils.bytes2HexString(p_memsz)
- +"\np_flags:"+Utils.bytes2HexString(p_flags)
- +"\np_align:"+Utils.bytes2HexString(p_align);
- }
- }
- public void printPhdrList(){
- for(int i=0;i<phdrList.size();i++){
- System.out.println();
- System.out.println("The "+(i+1)+" Program Header:");
- System.out.println(phdrList.get(i).toString());
- }
- }
- /**
- * typedef struct elf32_shdr {
- Elf32_Word sh_name;
- Elf32_Word sh_type;
- Elf32_Word sh_flags;
- Elf32_Addr sh_addr;
- Elf32_Off sh_offset;
- Elf32_Word sh_size;
- Elf32_Word sh_link;
- Elf32_Word sh_info;
- Elf32_Word sh_addralign;
- Elf32_Word sh_entsize;
- } Elf32_Shdr;
- */
- public static class elf32_shdr{
- public byte[] sh_name = new byte[4];
- public byte[] sh_type = new byte[4];
- public byte[] sh_flags = new byte[4];
- public byte[] sh_addr = new byte[4];
- public byte[] sh_offset = new byte[4];
- public byte[] sh_size = new byte[4];
- public byte[] sh_link = new byte[4];
- public byte[] sh_info = new byte[4];
- public byte[] sh_addralign = new byte[4];
- public byte[] sh_entsize = new byte[4];
- @Override
- public String toString(){
- return "sh_name:"+Utils.bytes2HexString(sh_name)/*Utils.byte2Int(sh_name)*/
- +"\nsh_type:"+Utils.bytes2HexString(sh_type)
- +"\nsh_flags:"+Utils.bytes2HexString(sh_flags)
- +"\nsh_add:"+Utils.bytes2HexString(sh_addr)
- +"\nsh_offset:"+Utils.bytes2HexString(sh_offset)
- +"\nsh_size:"+Utils.bytes2HexString(sh_size)
- +"\nsh_link:"+Utils.bytes2HexString(sh_link)
- +"\nsh_info:"+Utils.bytes2HexString(sh_info)
- +"\nsh_addralign:"+Utils.bytes2HexString(sh_addralign)
- +"\nsh_entsize:"+ Utils.bytes2HexString(sh_entsize);
- }
- }
- /****************sh_type********************/
- public static final int SHT_NULL = 0;
- public static final int SHT_PROGBITS = 1;
- public static final int SHT_SYMTAB = 2;
- public static final int SHT_STRTAB = 3;
- public static final int SHT_RELA = 4;
- public static final int SHT_HASH = 5;
- public static final int SHT_DYNAMIC = 6;
- public static final int SHT_NOTE = 7;
- public static final int SHT_NOBITS = 8;
- public static final int SHT_REL = 9;
- public static final int SHT_SHLIB = 10;
- public static final int SHT_DYNSYM = 11;
- public static final int SHT_NUM = 12;
- public static final int SHT_LOPROC = 0x70000000;
- public static final int SHT_HIPROC = 0x7fffffff;
- public static final int SHT_LOUSER = 0x80000000;
- public static final int SHT_HIUSER = 0xffffffff;
- public static final int SHT_MIPS_LIST = 0x70000000;
- public static final int SHT_MIPS_CONFLICT = 0x70000002;
- public static final int SHT_MIPS_GPTAB = 0x70000003;
- public static final int SHT_MIPS_UCODE = 0x70000004;
- /*****************sh_flag***********************/
- public static final int SHF_WRITE = 0x1;
- public static final int SHF_ALLOC = 0x2;
- public static final int SHF_EXECINSTR = 0x4;
- public static final int SHF_MASKPROC = 0xf0000000;
- public static final int SHF_MIPS_GPREL = 0x10000000;
- public void printShdrList(){
- for(int i=0;i<shdrList.size();i++){
- System.out.println();
- System.out.println("The "+(i+1)+" Section Header:");
- System.out.println(shdrList.get(i));
- }
- }
- public static class elf32_strtb{
- public byte[] str_name;
- public int len;
- @Override
- public String toString(){
- return "str_name:"+str_name
- +"len:"+len;
- }
- }
- }
有了結構定義,下面就來看看如何解析吧。
在解析之前我們需要將so文件讀取到byte[]中,定義一個數據結構類型
- public static ElfType32 type_32 = new ElfType32();
- byte[] fileByteArys = Utils.readFile("so/libhello-jni.so");
- if(fileByteArys == null){
- System.out.println("read file byte failed...");
- return;
- }
2、解析elf文件的頭部信息
關於這些字段的解釋,要看上面提到的那個pdf文件中的描述
這裏我們介紹幾個重要的字段,也是我們後面修改so文件的時候也會用到:
1)、e_phoff
這個字段是程序頭(Program Header)內容在整個文件的偏移值,我們可以用這個偏移值來定位程序頭的開始位置,用於解析程序頭信息
2)、e_shoff
這個字段是段頭(Section Header)內容在這個文件的偏移值,我們可以用這個偏移值來定位段頭的開始位置,用於解析段頭信息
3)、e_phnum
這個字段是程序頭的個數,用於解析程序頭信息
4)、e_shnum
這個字段是段頭的個數,用於解析段頭信息
5)、e_shstrndx
這個字段是String段在整個段列表中的索引值,這個用於後面定位String段的位置
按照上面的圖我們就可以很容易的解析
- /**
- * 解析Elf的頭部信息
- * @param header
- */
- private static void parseHeader(byte[] header, int offset){
- if(header == null){
- System.out.println("header is null");
- return;
- }
- /**
- * public byte[] e_ident = new byte[16];
- public short e_type;
- public short e_machine;
- public int e_version;
- public int e_entry;
- public int e_phoff;
- public int e_shoff;
- public int e_flags;
- public short e_ehsize;
- public short e_phentsize;
- public short e_phnum;
- public short e_shentsize;
- public short e_shnum;
- public short e_shstrndx;
- */
- type_32.hdr.e_ident = Utils.copyBytes(header, 0, 16);//魔數
- type_32.hdr.e_type = Utils.copyBytes(header, 16, 2);
- type_32.hdr.e_machine = Utils.copyBytes(header, 18, 2);
- type_32.hdr.e_version = Utils.copyBytes(header, 20, 4);
- type_32.hdr.e_entry = Utils.copyBytes(header, 24, 4);
- type_32.hdr.e_phoff = Utils.copyBytes(header, 28, 4);
- type_32.hdr.e_shoff = Utils.copyBytes(header, 32, 4);
- type_32.hdr.e_flags = Utils.copyBytes(header, 36, 4);
- type_32.hdr.e_ehsize = Utils.copyBytes(header, 40, 2);
- type_32.hdr.e_phentsize = Utils.copyBytes(header, 42, 2);
- type_32.hdr.e_phnum = Utils.copyBytes(header, 44,2);
- type_32.hdr.e_shentsize = Utils.copyBytes(header, 46,2);
- type_32.hdr.e_shnum = Utils.copyBytes(header, 48, 2);
- type_32.hdr.e_shstrndx = Utils.copyBytes(header, 50, 2);
- }
3、解析段頭(Section Header)信息
這個結構中字段見pdf中的描述吧,這裏就不做解釋了。後面我們會手動的構造這樣的一個數據結構,到時候在詳細說明每個字段含義。
按照這個結構。我們解析也簡單了:
- /**
- * 解析段頭信息內容
- */
- public static void parseSectionHeaderList(byte[] header, int offset){
- int header_size = 40;//40個字節
- int header_count = Utils.byte2Short(type_32.hdr.e_shnum);//頭部的個數
- byte[] des = new byte[header_size];
- for(int i=0;i<header_count;i++){
- System.arraycopy(header, i*header_size + offset, des, 0, header_size);
- type_32.shdrList.add(parseSectionHeader(des));
- }
- }
- private static elf32_shdr parseSectionHeader(byte[] header){
- ElfType32.elf32_shdr shdr = new ElfType32.elf32_shdr();
- /**
- * public byte[] sh_name = new byte[4];
- public byte[] sh_type = new byte[4];
- public byte[] sh_flags = new byte[4];
- public byte[] sh_addr = new byte[4];
- public byte[] sh_offset = new byte[4];
- public byte[] sh_size = new byte[4];
- public byte[] sh_link = new byte[4];
- public byte[] sh_info = new byte[4];
- public byte[] sh_addralign = new byte[4];
- public byte[] sh_entsize = new byte[4];
- */
- shdr.sh_name = Utils.copyBytes(header, 0, 4);
- shdr.sh_type = Utils.copyBytes(header, 4, 4);
- shdr.sh_flags = Utils.copyBytes(header, 8, 4);
- shdr.sh_addr = Utils.copyBytes(header, 12, 4);
- shdr.sh_offset = Utils.copyBytes(header, 16, 4);
- shdr.sh_size = Utils.copyBytes(header, 20, 4);
- shdr.sh_link = Utils.copyBytes(header, 24, 4);
- shdr.sh_info = Utils.copyBytes(header, 28, 4);
- shdr.sh_addralign = Utils.copyBytes(header, 32, 4);
- shdr.sh_entsize = Utils.copyBytes(header, 36, 4);
- return shdr;
- }
4、解析程序頭(Program Header)信息
這裏的字段,這裏也不做解釋了,看pdf文檔。
我們按照這個結構來進行解析:
- /**
- * 解析程序頭信息
- * @param header
- */
- public static void parseProgramHeaderList(byte[] header, int offset){
- int header_size = 32;//32個字節
- int header_count = Utils.byte2Short(type_32.hdr.e_phnum);//頭部的個數
- byte[] des = new byte[header_size];
- for(int i=0;i<header_count;i++){
- System.arraycopy(header, i*header_size + offset, des, 0, header_size);
- type_32.phdrList.add(parseProgramHeader(des));
- }
- }
- private static elf32_phdr parseProgramHeader(byte[] header){
- /**
- * public int p_type;
- public int p_offset;
- public int p_vaddr;
- public int p_paddr;
- public int p_filesz;
- public int p_memsz;
- public int p_flags;
- public int p_align;
- */
- ElfType32.elf32_phdr phdr = new ElfType32.elf32_phdr();
- phdr.p_type = Utils.copyBytes(header, 0, 4);
- phdr.p_offset = Utils.copyBytes(header, 4, 4);
- phdr.p_vaddr = Utils.copyBytes(header, 8, 4);
- phdr.p_paddr = Utils.copyBytes(header, 12, 4);
- phdr.p_filesz = Utils.copyBytes(header, 16, 4);
- phdr.p_memsz = Utils.copyBytes(header, 20, 4);
- phdr.p_flags = Utils.copyBytes(header, 24, 4);
- phdr.p_align = Utils.copyBytes(header, 28, 4);
- return phdr;
- }
5、驗證解析結果
那麼上面我們的解析工作做完了,爲了驗證我們的解析工作是否正確,我們需要給每個結構定義個打印函數,也就是從寫toString方法即可。
然後我們在使用readelf工具來查看so文件的各個結構內容,對比就可以知道解析的是否成功了。
解析代碼下載地址:http://download.csdn.net/detail/jiangwei0910410003/9204119
上面我們用的是Java代碼來進行解析的,爲了照顧廣大程序猿,所以給出一個C++版本的解析類:
- #include<iostream.h>
- #include<string.h>
- #include<stdio.h>
- #include "elf.h"
- /**
- 非常重要的一個宏,功能很簡單:
- P:需要對其的段地址
- ALIGNBYTES:對其的字節數
- 功能:將P值補充到時ALIGNBYTES的整數倍
- 這個函數也叫:頁面對其函數
- eg: 0x3e45/0x1000 == >0x4000
- */
- #define ALIGN(P, ALIGNBYTES) ( ((unsigned long)P + ALIGNBYTES -1)&~(ALIGNBYTES-1) )
- int addSectionFun(char*, char*, unsigned int);
- int main()
- {
- addSectionFun("D:\libhello-jni.so", ".jiangwei", 0x1000);
- return 0;
- }
- int addSectionFun(char *lpPath, char *szSecname, unsigned int nNewSecSize)
- {
- char name[50];
- FILE *fdr, *fdw;
- char *base = NULL;
- Elf32_Ehdr *ehdr;
- Elf32_Phdr *t_phdr, *load1, *load2, *dynamic;
- Elf32_Shdr *s_hdr;
- int flag = 0;
- int i = 0;
- unsigned mapSZ = 0;
- unsigned nLoop = 0;
- unsigned int nAddInitFun = 0;
- unsigned int nNewSecAddr = 0;
- unsigned int nModuleBase = 0;
- memset(name, 0, sizeof(name));
- if(nNewSecSize == 0)
- {
- return 0;
- }
- fdr = fopen(lpPath, "rb");
- strcpy(name, lpPath);
- if(strchr(name, '.'))
- {
- strcpy(strchr(name, '.'), "_new.so");
- }
- else
- {
- strcat(name, "_new");
- }
- fdw = fopen(name, "wb");
- if(fdr == NULL || fdw == NULL)
- {
- printf("Open file failed");
- return 1;
- }
- fseek(fdr, 0, SEEK_END);
- mapSZ = ftell(fdr);//源文件的長度大小
- printf("mapSZ:0x%x\n", mapSZ);
- base = (char*)malloc(mapSZ * 2 + nNewSecSize);//2*源文件大小+新加的Section size
- printf("base 0x%x \n", base);
- memset(base, 0, mapSZ * 2 + nNewSecSize);
- fseek(fdr, 0, SEEK_SET);
- fread(base, 1, mapSZ, fdr);//拷貝源文件內容到base
- if(base == (void*) -1)
- {
- printf("fread fd failed");
- return 2;
- }
- //判斷Program Header
- ehdr = (Elf32_Ehdr*) base;
- t_phdr = (Elf32_Phdr*)(base + sizeof(Elf32_Ehdr));
- for(i=0;i<ehdr->e_phnum;i++)
- {
- if(t_phdr->p_type == PT_LOAD)
- {
- //這裏的flag只是一個標誌位,去除第一個LOAD的Segment的值
- if(flag == 0)
- {
- load1 = t_phdr;
- flag = 1;
- nModuleBase = load1->p_vaddr;
- printf("load1 = %p, offset = 0x%x \n", load1, load1->p_offset);
- }
- else
- {
- load2 = t_phdr;
- printf("load2 = %p, offset = 0x%x \n", load2, load2->p_offset);
- }
- }
- if(t_phdr->p_type == PT_DYNAMIC)
- {
- dynamic = t_phdr;
- printf("dynamic = %p, offset = 0x%x \n", dynamic, dynamic->p_offset);
- }
- t_phdr ++;
- }
- //section header
- s_hdr = (Elf32_Shdr*)(base + ehdr->e_shoff);
- //獲取到新加section的位置,這個是重點,需要進行頁面對其操作
- printf("addr:0x%x\n",load2->p_paddr);
- nNewSecAddr = ALIGN(load2->p_paddr + load2->p_memsz - nModuleBase, load2->p_align);
- printf("new section add:%x \n", nNewSecAddr);
- if(load1->p_filesz < ALIGN(load2->p_paddr + load2->p_memsz, load2->p_align) )
- {
- printf("offset:%x\n",(ehdr->e_shoff + sizeof(Elf32_Shdr) * ehdr->e_shnum));
- //注意這裏的代碼的執行條件,這裏其實就是判斷section header是不是在文件的末尾
- if( (ehdr->e_shoff + sizeof(Elf32_Shdr) * ehdr->e_shnum) != mapSZ)
- {
- if(mapSZ + sizeof(Elf32_Shdr) * (ehdr->e_shnum + 1) > nNewSecAddr)
- {
- printf("無法添加節\n");
- return 3;
- }
- else
- {
- memcpy(base + mapSZ, base + ehdr->e_shoff, sizeof(Elf32_Shdr) * ehdr->e_shnum);//將Section Header拷貝到原來文件的末尾
- ehdr->e_shoff = mapSZ;
- mapSZ += sizeof(Elf32_Shdr) * ehdr->e_shnum;//加上Section Header的長度
- s_hdr = (Elf32_Shdr*)(base + ehdr->e_shoff);
- printf("ehdr_offset:%x",ehdr->e_shoff);
- }
- }
- }
- else
- {
- nNewSecAddr = load1->p_filesz;
- }
- printf("還可添加 %d 個節\n", (nNewSecAddr - ehdr->e_shoff) / sizeof(Elf32_Shdr) - ehdr->e_shnum - 1);
- int nWriteLen = nNewSecAddr + ALIGN(strlen(szSecname) + 1, 0x10) + nNewSecSize;//添加section之後的文件總長度:原來的長度 + section name + section size
- printf("write len %x\n",nWriteLen);
- char *lpWriteBuf = (char *)malloc(nWriteLen);//nWriteLen :最後文件的總大小
- memset(lpWriteBuf, 0, nWriteLen);
- //ehdr->e_shstrndx是section name的string表在section表頭中的偏移值,修改string段的大小
- s_hdr[ehdr->e_shstrndx].sh_size = nNewSecAddr - s_hdr[ehdr->e_shstrndx].sh_offset + strlen(szSecname) + 1;
- strcpy(lpWriteBuf + nNewSecAddr, szSecname);//添加section name
- //以下代碼是構建一個Section Header
- Elf32_Shdr newSecShdr = {0};
- newSecShdr.sh_name = nNewSecAddr - s_hdr[ehdr->e_shstrndx].sh_offset;
- newSecShdr.sh_type = SHT_PROGBITS;
- newSecShdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
- nNewSecAddr += ALIGN(strlen(szSecname) + 1, 0x10);
- newSecShdr.sh_size = nNewSecSize;
- newSecShdr.sh_offset = nNewSecAddr;
- newSecShdr.sh_addr = nNewSecAddr + nModuleBase;
- newSecShdr.sh_addralign = 4;
- //修改Program Header信息
- load1->p_filesz = nWriteLen;
- load1->p_memsz = nNewSecAddr + nNewSecSize;
- load1->p_flags = 7; //可讀 可寫 可執行
- //修改Elf header中的section的count值
- ehdr->e_shnum++;
- memcpy(lpWriteBuf, base, mapSZ);//從base中拷貝mapSZ長度的字節到lpWriteBuf
- memcpy(lpWriteBuf + mapSZ, &newSecShdr, sizeof(Elf32_Shdr));//將新加的Section Header追加到lpWriteBuf末尾
- //寫文件
- fseek(fdw, 0, SEEK_SET);
- fwrite(lpWriteBuf, 1, nWriteLen, fdw);
- fclose(fdw);
- fclose(fdr);
- free(base);
- free(lpWriteBuf);
- return 0;
- }
C++代碼下載:http://download.csdn.net/detail/jiangwei0910410003/9204139