首页
社区
课程
招聘
[原创]Galgame汉化中的逆向(特别篇一):ArmArm64_ELF中汉化字符串超长修改方法
发表于: 2021-8-11 21:03 17632

[原创]Galgame汉化中的逆向(特别篇一):ArmArm64_ELF中汉化字符串超长修改方法

2021-8-11 21:03
17632

by devseed, 本贴论坛和我的博客同时发布

之前发的Galgame汉化中的逆向系列,大多是结合具体游戏来谈谈分析思路与汉化方法。大多数主机游戏可执行文件都是魔改的ELF文件(比如说psv,ps4系统内核就是由FreeBSD修改而来的),不同于以x86架构为主的pc平台,主机平台架构可谓是百花齐放:psp,ps2是mips架构,ps3是powerpc架构,ps4是x86架构,psv是arm架构,switch是arm64架构。ps4的x86架构修改方法和pc版类似,powerpc架构的汇编暂时还没研究,mips架构汇编相关的分析,今后有时间可能会更新教程。由于arm指令一般情况下都是4字节定长(还有2字节的thumb指令),movldw等指令的立即数有范围限制,寻址方式多为相对于PC的偏移寻址,这与x86里立即数可以直接写VA地址(如FF 15系列长跳转指令、b8系列的mov)有很大区别。因此这篇作为《galgame汉化中的逆向》系列教程的补充,来聊聊ELF结构、如何对ELF修改、Arm汇编寻址方法以及如何修改Arm汇编中字符串的指针

一般来说主机游戏剧本、字库等都在资源文件(封包文件)中,可执行文件中只有少量的系统文本。这部分通常也不需要汉化比原字符长(因为系统文本一般没有太多含义,且汉语本身就比较简洁),因此直接替换二进制字符就行了。但是对于一些特列,即字库或剧本整体封在了可执行文件中,就要增加区段和用汇编修改指针把字符串重定向到新增区段中了。如psv、switch版的Gnosia,和psv、ps3版的WhiteAlbum2,修改eboot方法详见PSV版WA2汉化移植

为了更直观地说明原理和看到运行结果,本篇教程将不以具体游戏为例,而是用arm版helloword程序,讲解一下修改armarm64 ELF的方法。理论上适用于psv、swich、android平台的可执行文件或动态库,根据不同平台可能需要再转换为其对应的魔改ELF格式。

本篇教程需要的工具:

参考网站:

https://www.mztn.org/dragon/arm6405str.html

http://armconverter.com/

安装脚本如下:

最简单的hello world程序代码:

交叉编译命令行:

运行命令行:

Linux系统的可执行文件和动态库为ELF格式,与windows的pe类似。里面的几个重要结构为:ELF headerSection Header Table‘、Program Header Table。关于sectionsegment关系如下

ELF文件的段结构就是由段表决定的。
编译器、链接器和装载器都是依靠段表来定位和访问各个段的属性的。
段表在ELF文件中的位置由ELF文件头的“e_shoff”成员决定的。

常用readelf来查看elf结构,objdump来查看反汇编,命令行如下:

关于添加新区段,可以自己手动修改ELF文件头对应的索引增加区段,可以参见android so手动增加区段。我以前也写过windowsPE增加区段的轮子simpledpack,这次就不再自己造轮子了,直接用lief解析ELF了。这个库逻辑挺清晰的:

lief.ELF.parse(path)-> LIEF::ELF::Binary,解析elf,

lief.ELF.Section(name, type),创建新section

a. 添加区段并patch例子:

b. 扩容区段例子:

c. sym替换(类似于IAThook)

32位的arm通常是通过当前PC寄存器找到内存偏移表地址,再通过表中偏移计算出最终地址,相当于两次对内存寻址找到最终地址。通常用add pc, Rdadr Rd, offset,之后ldr Rd来获得最终地址。内存偏移表通常在一个函数的结尾处(BLX LR函数返回后),每项存储4字节偏移。

thumb指令为2字节定长,在psv的eboot和android的so里面会经常出现这种指令集。

这种情况下内存偏移表存储的是相对于add Rd, pc的偏移,即value_addr-pc-4,下面通过实例来分析:

可见ida里面机器码为文件中的字节顺序,指令转义为了ldr伪指令;而objdump中机器码为小端整数,指令转换成直接对应汇编的样子,因此学习arm汇编看objdump比较直观。

13f78:4825 ldr r0, [pc, #148]为访问内存偏移表内容指令,偏移表地址13f78h+4+#148(94h)=14010h,即把偏移表存储的偏移34BF0h载入r0;偏移表里的内容为.text:00014010 F0 4B 03 00,是相对于13f7c: 4478 add r0, pc的偏移;13f7c:4478 add r0, pc,最终地址为34BF0h+13F7Ch+4=48B70h

arm 4字节ldradr伪指令转换为add register, pc [#offset]。机器码的存储格式如下:

同样有内存偏移表,但此偏移表存储的偏移值为相对于偏移表地址的偏移。下面为编译的hello_arm_start函数的反汇编内容:

658:f8df a024 ldr.w sl, [pc, #36]为加载内存偏移表内容指令,658h+#36(24h)+4=680h内存偏移表地址,加载内存偏移表存储的偏移值1092chs1寄存器;65c:a308 add r3, pc, #32,紧接着将r3载入内存偏移表地址,即65ch+#32(20h)+4=680h65e:449a add sl, r3得到最终地址1092ch+680h=10fach,因此这里内存偏移表内存储的偏移是最终地址相对于内存偏移表地址的偏移。

由于arm汇编是用PC内存偏移表进行寻址,所以修改ldr的最终读取的地址仅需要修改内存偏移表中的偏移。

修改arm汇编字符串地址的测试用例如下:用lief增加区段,内容为"hooked str hello world!\n",capstone反汇编解析ldr内存偏移表地址,修改内存偏移表内的值改为新增加区段的字符串相对偏移(注意偏移值是相对于add pc处的,脚本里统一用VA相减表示)

运行patch脚本后,qemu测试hook成功!

arm_hookstr

arm64arm同样是定长指令和相对于PC的寻址,只不过arm64没有内存偏移表了,用adrp @pageadd|ldr @pageoff来寻址。

ADRP指令是以页为单位的大范围的地址读取指令,P为page, pageoffpage offset,这里填写的地址是最终地址的页基址,汇编会自动把opcode转换成相对于pc页基址的地址。

符号扩展一个21位的offset(immhi+immlo)。向左移动12位,将PC的值的低12位清零,然后把这两者相加,结果写入到Xd寄存器,用来得到一块含有label的4KB对齐内存区域的base地址(也就是说label所在的地址,一定落在这个4KB的内存区域里,指令助记符里Page也就是这个意思), 可用来寻址 +/- 4GB的范围(2^33次幂)。

下面是几种指令的机器码比较:

下面代码说明了,adrp的机器码immhi+immlo存储的是相对于当前页面的页偏移0x22000,但是反汇编后显示的则是目标的VA,即adrp x0, #0x25000(当此指令在0x3000处时候,cs.disasm(code, 0x3000))。

adrp @page 找到目标页地址,add @pageoff加上页内偏移。如果用ida的keypatch修改,需要去掉@page@pageoff后缀,手动来计算目标页地址和页内偏移才行。ida和objdump的反汇编代码如下:

下面的python脚本说明了如何用capstone进行反汇编,如何手动求目标页地址页内偏移,以及之后用keystone进行汇编更新adrp @pageadd @pageoff指令。

运行patch脚本后,qemu测试成功!

arm64_hookstr

这篇教程虽然难度不高,本来以为很快就能写完了,但是写了好久。很多东西叙述起来很麻烦,我尽量结合实例清晰和有条理性地讲述,不知不觉中写了好多东西。目前关于主机系列的汉化教程非常少,以往很多的教程也都随着论坛的关闭等无法访问了。同样,比起x86的汇编的修改,arm64 elf之类的分析也不多。我系统地做《galgame汉化中的逆向》系列是想总结一下汉化方法,结合我自身对一些问题的思考和理解,以使汉化逆向这门技术今后能更好地传承下去。

 
 
 
 
 
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf # arm32
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu # arm64
sudo apt-get install qemu-user-static binfmt-support
sudo apt-get install gdb-multiarch
pip3 install lief keystone-engine capstone
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf # arm32
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu # arm64
sudo apt-get install qemu-user-static binfmt-support
sudo apt-get install gdb-multiarch
pip3 install lief keystone-engine capstone
# include <iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
}
# include <iostream>
using namespace std;
int main()
{
    cout<<"hello world"<<endl;
}
cd build
arm-linux-gnueabihf-g++ ./../hello.cpp -o hello_arm
aarch64-linux-gnu-g++ ./../hello.cpp -o hello_arm64
cd build
arm-linux-gnueabihf-g++ ./../hello.cpp -o hello_arm
aarch64-linux-gnu-g++ ./../hello.cpp -o hello_arm64
qemu-arm-static -L /usr/arm-linux-gnueabihf/ ./hello_arm
qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./hello_arm64
qemu-arm-static -L /usr/arm-linux-gnueabihf/ ./hello_arm
qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./hello_arm64
#define EI_NIDENT 16
 
 struct Elf32_Ehdr {
   unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
   Elf32_Half e_type;                // Type of file (see ET_* below)
   Elf32_Half e_machine;   // Required architecture for this file (see EM_*)
   Elf32_Word e_version;   // Must be equal to 1
   Elf32_Addr e_entry;     // Address to jump to in order to start program
   Elf32_Off e_phoff;      // Program header table's file offset, in bytes
   Elf32_Off e_shoff;      // Section header table's file offset, in bytes
   Elf32_Word e_flags;     // Processor-specific flags
   Elf32_Half e_ehsize;    // Size of ELF header, in bytes
   Elf32_Half e_phentsize; // Size of an entry in the program header table
   Elf32_Half e_phnum;     // Number of entries in the program header table
   Elf32_Half e_shentsize; // Size of an entry in the section header table
   Elf32_Half e_shnum;     // Number of entries in the section header table
   Elf32_Half e_shstrndx;  // Sect hdr table index of sect name string table
};
typedef struct {
         Elf64
        ...
} Elf64_Ehdr;
#define EI_NIDENT 16
 
 struct Elf32_Ehdr {
   unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
   Elf32_Half e_type;                // Type of file (see ET_* below)
   Elf32_Half e_machine;   // Required architecture for this file (see EM_*)
   Elf32_Word e_version;   // Must be equal to 1
   Elf32_Addr e_entry;     // Address to jump to in order to start program
   Elf32_Off e_phoff;      // Program header table's file offset, in bytes
   Elf32_Off e_shoff;      // Section header table's file offset, in bytes
   Elf32_Word e_flags;     // Processor-specific flags
   Elf32_Half e_ehsize;    // Size of ELF header, in bytes
   Elf32_Half e_phentsize; // Size of an entry in the program header table
   Elf32_Half e_phnum;     // Number of entries in the program header table
   Elf32_Half e_shentsize; // Size of an entry in the section header table
   Elf32_Half e_shnum;     // Number of entries in the section header table
   Elf32_Half e_shstrndx;  // Sect hdr table index of sect name string table
};
typedef struct {
         Elf64
        ...
} Elf64_Ehdr;
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...
 }Elf64_Shdr;
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...
 }Elf64_Shdr;
typedef struct {
   Elf32_Word p_type;   // Type of segment
   Elf32_Off p_offset;  // File offset where segment is located, in bytes
   Elf32_Addr p_vaddr;  // Virtual address of beginning of segment
   Elf32_Addr p_paddr;  // Physical address of beginning of segment (OS-specific)
   Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
   Elf32_Word p_memsz;  // Num. of bytes in mem image of segment (may be zero)
   Elf32_Word p_flags;  // Segment flags
   Elf32_Word p_align;  // Segment alignment constraint
} Elf32_Phdr;
 
typedef struct {
        Elf64_Word
        ...   
} Elf64_Phdr;
typedef struct {
   Elf32_Word p_type;   // Type of segment
   Elf32_Off p_offset;  // File offset where segment is located, in bytes
   Elf32_Addr p_vaddr;  // Virtual address of beginning of segment
   Elf32_Addr p_paddr;  // Physical address of beginning of segment (OS-specific)
   Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
   Elf32_Word p_memsz;  // Num. of bytes in mem image of segment (may be zero)
   Elf32_Word p_flags;  // Segment flags
   Elf32_Word p_align;  // Segment alignment constraint
} Elf32_Phdr;
 
typedef struct {
        Elf64_Word
        ...   
} Elf64_Phdr;
readelf -h|--file-header elffile //查看elf头,可以与下面多个选项组合
readelf -S|--sections elffile  //查看elf section头
readelf -l|-–segments elffile //查看elf segment头
readelf -x|--hexdump .sect_name|number elffile// 通过数字或name hexdump section
readelf -r elffile //查看elf 重定位
readelf -d elffile //查看elf .dynamic段, needed
 
objdump -f|--file-headers elffile //显示obj类型
objdump -x|--all-headers libxxxxx.so | grep NEEDED //-x 显示所可用的头信息
objdump -s [-j name] elf //-s 对section反汇编, -j 显示section的信息, 如.data
objdump -d [--start-address=address] [--stop-address=address] elffile //反编译
 
hexdump [-s|--skip skip_offset] [-n|--length size] <file>
-C 显示asci和hex
-d|x 两字节10进制,16进制显示
readelf -h|--file-header elffile //查看elf头,可以与下面多个选项组合
readelf -S|--sections elffile  //查看elf section头
readelf -l|-–segments elffile //查看elf segment头
readelf -x|--hexdump .sect_name|number elffile// 通过数字或name hexdump section
readelf -r elffile //查看elf 重定位
readelf -d elffile //查看elf .dynamic段, needed
 
objdump -f|--file-headers elffile //显示obj类型
objdump -x|--all-headers libxxxxx.so | grep NEEDED //-x 显示所可用的头信息
objdump -s [-j name] elf //-s 对section反汇编, -j 显示section的信息, 如.data
objdump -d [--start-address=address] [--stop-address=address] elffile //反编译
 
hexdump [-s|--skip skip_offset] [-n|--length size] <file>
-C 显示asci和hex
-d|x 两字节10进制,16进制显示
libsdl_main_jni = lief.parse("hello")
sec_hookstr = lief.ELF.Section(".hookstr", lief.ELF.SECTION_TYPES.PROGBITS)
sec_hookstr += lief.ELF.SECTION_FLAGS.EXECINSTR
sec_hookstr.alignment = 4
sec_hookstr.content = list(bytes('hooked str hello world!\n', encoding='ansi'))
# add section will automaticlly add to segment, return section to see addr and size
sec_hookstr = libsdl_main_jni.add(sec_hookstr)
 
# para1, stored str address  (this can be seen from ldr  -4K~4K is the base addr)
# para2, edit stored str address content, hookstr rva 7000 -  base 15CA
libsdl_main_jni.patch_address(0x15D0, [0X36, 0X5A])
libsdl_main_jni.write("hello_hook")
libsdl_main_jni = lief.parse("hello")
sec_hookstr = lief.ELF.Section(".hookstr", lief.ELF.SECTION_TYPES.PROGBITS)
sec_hookstr += lief.ELF.SECTION_FLAGS.EXECINSTR
sec_hookstr.alignment = 4
sec_hookstr.content = list(bytes('hooked str hello world!\n', encoding='ansi'))
# add section will automaticlly add to segment, return section to see addr and size
sec_hookstr = libsdl_main_jni.add(sec_hookstr)
 
# para1, stored str address  (this can be seen from ldr  -4K~4K is the base addr)
# para2, edit stored str address content, hookstr rva 7000 -  base 15CA
libsdl_main_jni.patch_address(0x15D0, [0X36, 0X5A])
libsdl_main_jni.write("hello_hook")
for section in libsdl_main_jni.sections:
    if section.name == '.rodata':
        print(hex(section.offset), section.size)
        byte_arr = list(bytes('/data/data/cn.natdon.onscripterv2yuri/lib/libapp_%s.so\0', encoding='ansi'))
        arr_offset = section.offset+section.size
        section.size += len(byte_arr)
        libsdl_main_jni.segments[1].virtual_size += len(byte_arr)
        libsdl_main_jni.segments[1].physical_size += len(byte_arr)
        libsdl_main_jni.patch_address(arr_offset, byte_arr)
        libsdl_main_jni.patch_address(0x21C8, list((arr_offset-0x2104).to_bytes(2, 'little')))
for section in libsdl_main_jni.sections:
    if section.name == '.rodata':
        print(hex(section.offset), section.size)
        byte_arr = list(bytes('/data/data/cn.natdon.onscripterv2yuri/lib/libapp_%s.so\0', encoding='ansi'))
        arr_offset = section.offset+section.size
        section.size += len(byte_arr)
        libsdl_main_jni.segments[1].virtual_size += len(byte_arr)
        libsdl_main_jni.segments[1].physical_size += len(byte_arr)
        libsdl_main_jni.patch_address(arr_offset, byte_arr)
        libsdl_main_jni.patch_address(0x21C8, list((arr_offset-0x2104).to_bytes(2, 'little')))
fopen_sym = next(filter(lambda e : e.name == "fopen", libxxx.imported_symbols))
fopen_sym.name = "fopen_saf"
fopen_sym = next(filter(lambda e : e.name == "fopen", libxxx.imported_symbols))
fopen_sym.name = "fopen_saf"
 
// ida libapp_onscripter-32bpp.so
.text:00013F78 25 48  LDR  R0, =(aUsageOnscripte - 0x13F80) ; "Usage: onscripter ...
;aUsageOnscripte 00048B70, 0X13F7C+4=0x13F80, 0X48B70-0x13F80=34BF0, 相对于add pc偏移
.text:00013F7A 08 B5        PUSH       {R3,LR}
.text:00013F7C 78 44        ADD         R0, PC  ; "Usage: onscripter [option ...]\n"
.text:00013F7E FF F7 E5 FF  BL          sub_13F4C
....
.text:00014010 F0 4B 03 00 off_14010       DCD aUsageOnscripte - 0x13F80
 
// arm-linux-gnueabihf-objdump -d --start-address 0x13f78 --stop-address 0x14014 libapp_onscripter-32bpp.so
13f78:       4825            ldr     r0, [pc, #148]; 94h,(14010 <_Z10optionHelpv+0x98>)
13f7a:       b508            push    {r3, lr}
13f7c:       4478            add     r0, pc
13f7e:       f7ff ffe5       bl      13f4c <__gnu_Unwind_Find_exidx@plt+0x34>
// ida libapp_onscripter-32bpp.so
.text:00013F78 25 48  LDR  R0, =(aUsageOnscripte - 0x13F80) ; "Usage: onscripter ...
;aUsageOnscripte 00048B70, 0X13F7C+4=0x13F80, 0X48B70-0x13F80=34BF0, 相对于add pc偏移
.text:00013F7A 08 B5        PUSH       {R3,LR}
.text:00013F7C 78 44        ADD         R0, PC  ; "Usage: onscripter [option ...]\n"
.text:00013F7E FF F7 E5 FF  BL          sub_13F4C
....
.text:00014010 F0 4B 03 00 off_14010       DCD aUsageOnscripte - 0x13F80
 
// arm-linux-gnueabihf-objdump -d --start-address 0x13f78 --stop-address 0x14014 libapp_onscripter-32bpp.so
13f78:       4825            ldr     r0, [pc, #148]; 94h,(14010 <_Z10optionHelpv+0x98>)
13f7a:       b508            push    {r3, lr}
13f7c:       4478            add     r0, pc
13f7e:       f7ff ffe5       bl      13f4c <__gnu_Unwind_Find_exidx@plt+0x34>
 
        31      27  26  25 24                     05  00
LDR32    0 0    0 1 1    0    0 0    imm19 (4倍されて, ±1MB)    Rt(5bit)
        31      27  26  25 24                     05  00
LDR32    0 0    0 1 1    0    0 0    imm19 (4倍されて, ±1MB)    Rt(5bit)
.text:00000648             _start
.text:00000648 4F F0 00 0B     MOV.W           R11, #0
.text:0000064C 4F F0 00 0E     MOV.W           LR, #0
.text:00000650 02 BC           POP             {R1}    ; argc
.text:00000652 6A 46           MOV             R2, SP  ; ubp_av
.text:00000654 04 B4           PUSH            {R2}    ; stack_end
.text:00000656 01 B4           PUSH            {R0}    ; rtld_fini
.text:00000658 DF F8 24 A0     LDR.W           R10, =($_GLOBAL_OFFSET_TABLE_ - 0x680)
; $_GLOBAL_OFFSET_TABLE_ 10FAC = 680 + 1092c 相对于偏移表的偏移。
.text:0000065C 08 A3           ADR             R3, off_680
.text:0000065E 9A 44           ADD             R10, R3 ; $_GLOBAL_OFFSET_TABLE_
.text:00000660 DF F8 20 C0     LDR.W           R12, =(__libc_csu_fini_ptr - 0x10FAC)
.text:00000664 5A F8 0C C0     LDR.W           R12, [R10,R12] ; __libc_csu_fini
.text:00000668 4D F8 04 CD     PUSH.W          {R12}   ; fini
.text:0000066C 06 4B           LDR             R3, =(__libc_csu_init_ptr - 0x10FAC)
.text:0000066E 5A F8 03 30     LDR.W           R3, [R10,R3] ; __libc_csu_init ; init
.text:00000672 06 48           LDR             R0, =(main_ptr - 0x10FAC)
.text:00000674 5A F8 00 00     LDR.W           R0, [R10,R0] ; main ; main
.text:00000678 FF F7 D4 EF     BLX             __libc_start_main
.text:0000067C FF F7 BA EF     BLX             abort
.text:00000680 2C 09 01 00 off_680         DCD $_GLOBAL_OFFSET_TABLE_ - 0x680
.text:00000684 40 00 00 00 off_684         DCD __libc_csu_fini_ptr - 0x10FAC
.text:00000688 38 00 00 00 off_688         DCD __libc_csu_init_ptr - 0x10FAC
.text:0000068C 2C 00 00 00 off_68C         DCD main_ptr - 0x10FAC
 
// objdump -d hello_arm
00000648 <_start>:
 648:   f04f 0b00       mov.w   fp, #0
 64c:   f04f 0e00       mov.w   lr, #0
 650:   bc02            pop     {r1}
 652:   466a            mov     r2, sp
 654:   b404            push    {r2}
 656:   b401            push    {r0}
 658:   f8df a024       ldr.w   sl, [pc, #36]   ; 65ch+24h=680 <_start+0x38>
 65c:   a308            add     r3, pc, #32     ; (adr r3, 680 <_start+0x38>)
 65e:   449a            add     sl, r3
 660:   f8df c020       ldr.w   ip, [pc, #32]   ; 684 <_start+0x3c>
 664:   f85a c00c       ldr.w   ip, [sl, ip]
 668:   f84d cd04       str.w   ip, [sp, #-4]!
 66c:   4b06            ldr     r3, [pc, #24]   ; (688 <_start+0x40>)
 66e:   f85a 3003       ldr.w   r3, [sl, r3]
 672:   4806            ldr     r0, [pc, #24]   ; (68c <_start+0x44>)
 674:   f85a 0000       ldr.w   r0, [sl, r0]
 678:   f7ff efd4       blx     624 <__libc_start_main@plt>
 67c:   f7ff efba       blx     5f4 <abort@plt>
 680:   0001092c        .word   0x0001092c
 684:   00000040        .word   0x00000040
 688:   00000038        .word   0x00000038
 68c:   0000002c        .word   0x0000002c
.text:00000648             _start
.text:00000648 4F F0 00 0B     MOV.W           R11, #0
.text:0000064C 4F F0 00 0E     MOV.W           LR, #0
.text:00000650 02 BC           POP             {R1}    ; argc
.text:00000652 6A 46           MOV             R2, SP  ; ubp_av
.text:00000654 04 B4           PUSH            {R2}    ; stack_end
.text:00000656 01 B4           PUSH            {R0}    ; rtld_fini
.text:00000658 DF F8 24 A0     LDR.W           R10, =($_GLOBAL_OFFSET_TABLE_ - 0x680)
; $_GLOBAL_OFFSET_TABLE_ 10FAC = 680 + 1092c 相对于偏移表的偏移。
.text:0000065C 08 A3           ADR             R3, off_680
.text:0000065E 9A 44           ADD             R10, R3 ; $_GLOBAL_OFFSET_TABLE_
.text:00000660 DF F8 20 C0     LDR.W           R12, =(__libc_csu_fini_ptr - 0x10FAC)
.text:00000664 5A F8 0C C0     LDR.W           R12, [R10,R12] ; __libc_csu_fini
.text:00000668 4D F8 04 CD     PUSH.W          {R12}   ; fini
.text:0000066C 06 4B           LDR             R3, =(__libc_csu_init_ptr - 0x10FAC)
.text:0000066E 5A F8 03 30     LDR.W           R3, [R10,R3] ; __libc_csu_init ; init
.text:00000672 06 48           LDR             R0, =(main_ptr - 0x10FAC)
.text:00000674 5A F8 00 00     LDR.W           R0, [R10,R0] ; main ; main
.text:00000678 FF F7 D4 EF     BLX             __libc_start_main
.text:0000067C FF F7 BA EF     BLX             abort
.text:00000680 2C 09 01 00 off_680         DCD $_GLOBAL_OFFSET_TABLE_ - 0x680
.text:00000684 40 00 00 00 off_684         DCD __libc_csu_fini_ptr - 0x10FAC
.text:00000688 38 00 00 00 off_688         DCD __libc_csu_init_ptr - 0x10FAC
.text:0000068C 2C 00 00 00 off_68C         DCD main_ptr - 0x10FAC
 
// objdump -d hello_arm
00000648 <_start>:
 648:   f04f 0b00       mov.w   fp, #0

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 9
支持
分享
最新回复 (5)
雪    币: 4
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
up主很勤劳,学习了( ´▽` )
2021-8-11 21:11
0
雪    币: 5029
活跃值: (4798)
能力值: ( LV10,RANK:171 )
在线值:
发帖
回帖
粉丝
3
感谢分享,赞一个!
2021-8-11 23:37
0
雪    币: 7
活跃值: (4331)
能力值: ( LV9,RANK:270 )
在线值:
发帖
回帖
粉丝
4
师傅的博客做的真用心。
2021-8-13 10:52
0
雪    币: 864
活跃值: (5124)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2021-8-21 09:48
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
Hi  up主你好,目前有一款UE4研发的游戏项目,想与你洽谈外包合作。请问方便留下邮箱等联系方式吗?
2022-1-19 18:33
0
游客
登录 | 注册 方可回帖
返回
//