如何取消引用 DWARF 中的引用
How to dereference a reference in DWARF
如何通过 DWARF 引用获取我的变量地址?
例如我们有下一个结构:
struct sub_struct
{
int a, b;
sub_struct(int a, int b) : a(a), b(b) {}
}
struct main_struct
{
sub_struct & as_ref;
int c, d;
main_struct(sub_struct & ss) : as_ref(ss), c(0x100), d(0x101) {}
}
之后我们在全局环境中初始化这个结构:
sub_struct test_sub(0x10, 0x11);
main_struct test_inst(sub_struct);
实际上test_inst.as_ref应该引用结构test_sub。我想获取存储在 as_ref 引用中的变量的位置。
如果我读取编译代码的矮文件,那么我将得到我创建的结构:
Compilation Unit @ offset 0x1a80bf:
Length: 0x11e (32-bit)
Version: 3
Abbrev Offset: 0xd3e6
Pointer Size: 4
<0><1a80ca>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1a814d> DW_AT_stmt_list : 0x8e02a
<1a8151> DW_AT_macro_info : 0xc6fb
<1><1a819b>: Abbrev Number: 3 (DW_TAG_variable)
<1a819c> DW_AT_name : test_inst
<1a81ad> DW_AT_type : <0x1a7643>
<1a81b6> DW_AT_location : 5 byte block: 3 50 6e ff 1f (DW_OP_addr: 1fff6e50)
<1a81bc> Unknown AT value: 2768: 1
<1><1a81e0>: Abbrev Number: 0
Compilation Unit @ offset 0x1a829e:
Length: 0xb8 (32-bit)
Version: 3
Abbrev Offset: 0xd3e6
Pointer Size: 4
<0><1a82a9>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1a832c> DW_AT_stmt_list : 0x8e02a
<1a8330> DW_AT_macro_info : 0xc6fb
<1><1a8334>: Abbrev Number: 3 (DW_TAG_variable)
<1a8335> DW_AT_name : test_sub
<1a834a> DW_AT_type : <0x1a761a>
<1a8352> DW_AT_location : 5 byte block: 3 48 7d ff 1f (DW_OP_addr: 1fff7d48)
<1a8358> Unknown AT value: 2768: 1
<1><1a8359>: Abbrev Number: 0
如您所见,test_inst 位于 0x1fff6e50 地址。而 test_sub 位于 0x1fff6e48。这是对的。如果我们要检查内存,那么:
- test_sub.a 位于 0x1fff6e48
- test_sub.b 位于 0x1fff6e4c
- test_inst.as_ref 应该位于 0x1fff6e50
- test_inst.c 位于 0x1fff6e54
- test_inst.d 位于 0x1fff6e58
我想知道如何手动查找 0x1fff6e48 地址,如果我在 as_ref.
中只有参考
main_struct 的矮人信息是这样的:
<1><1a7643>: Abbrev Number: 40 (DW_TAG_structure_type)
<1a7644> DW_AT_sibling : <0x1a76cf>
<1a7648> DW_AT_name : test_struct
<1a7654> DW_AT_byte_size : 44
<2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
<1a7656> DW_AT_type : <0x1a683a>
<1a7658> DW_AT_accessibility: 1 (public)
<1a7659> DW_AT_name : as_ref
<1a7660> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
<2><1a7663>: Abbrev Number: 44 (DW_TAG_member)
<1a7664> DW_AT_type : <0x1a6833>
<1a7666> DW_AT_accessibility: 1 (public)
<1a7667> DW_AT_name : c
<1a7669> DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
<2><1a766c>: Abbrev Number: 44 (DW_TAG_member)
<1a766d> DW_AT_type : <0x1a6833>
<1a766f> DW_AT_accessibility: 1 (public)
<1a7670> DW_AT_name : d
<1a7672> DW_AT_data_member_location: 2 byte block: 23 8 (DW_OP_plus_uconst: 8)
<2><1a76ce>: Abbrev Number: 0
as_ref类型参考这个:
<1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
<1a683b> DW_AT_type : <0x1a761a>
这将被引用:
<1><1a761a>: Abbrev Number: 40 (DW_TAG_structure_type)
<1a761b> DW_AT_sibling : <0x1a7643>
<1a761f> DW_AT_name : sub_struct
<1a762f> DW_AT_byte_size : 8
<2><1a7630>: Abbrev Number: 44 (DW_TAG_member)
<1a7631> DW_AT_type : <0x1a6833>
<1a7633> DW_AT_accessibility: 1 (public)
<1a7634> DW_AT_name : a
<1a7636> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
<2><1a7639>: Abbrev Number: 44 (DW_TAG_member)
<1a763a> DW_AT_type : <0x1a6833>
<1a763c> DW_AT_accessibility: 1 (public)
<1a763d> DW_AT_name : b
<1a763f> DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
<2><1a7642>: Abbrev Number: 0
TLDR:指针和引用在 hookd 下是一样的。 as_ref
包含引用的地址 sub_struct
。
这告诉您 as_ref
位于偏移量 0(因此为 0x1fff6e50):
<2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
<1a7656> DW_AT_type : <0x1a683a>
<1a7658> DW_AT_accessibility: 1 (public)
<1a7659> DW_AT_name : as_ref
<1a7660> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
其类型为:
<1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
<1a683b> DW_AT_type : <0x1a761a>
这意味着它是对另一种类型的引用。引用和指针在本质上是一样的:它们包含另一个变量的地址。
进程内部:
void* main_struct_addr = 0x1fff6e50; // from DWARF
std::uint64_t as_ref_offset = 0; // from DWARF
void* main_as_ref_addr = (char*) main_struct_addr + as_ref_offset;
void as_addr = *(void**) main_a_ref_addr;
assert(as_adddr == (void*) 0x1fff6e48);
来自另一个进程:
std::uint64_t main_struct_addr = 0x1fff6e50; // from DWARF
std::uint64_t as_ref_offset = 0; // from DWARF
std::uint64_t main_as_ref_addr = main_struct_addr + as_ref_offset;
errno = 0;
void* as_addr = (void*) ptrace(PTRACE_PEEKDATA, pid, (void*) main_as_ref_addr, NULL);
if (errno) { ... }
assert(as_adddr == (void*) 0x1fff6e48);
如何通过 DWARF 引用获取我的变量地址?
例如我们有下一个结构:
struct sub_struct
{
int a, b;
sub_struct(int a, int b) : a(a), b(b) {}
}
struct main_struct
{
sub_struct & as_ref;
int c, d;
main_struct(sub_struct & ss) : as_ref(ss), c(0x100), d(0x101) {}
}
之后我们在全局环境中初始化这个结构:
sub_struct test_sub(0x10, 0x11);
main_struct test_inst(sub_struct);
实际上test_inst.as_ref应该引用结构test_sub。我想获取存储在 as_ref 引用中的变量的位置。
如果我读取编译代码的矮文件,那么我将得到我创建的结构:
Compilation Unit @ offset 0x1a80bf:
Length: 0x11e (32-bit)
Version: 3
Abbrev Offset: 0xd3e6
Pointer Size: 4
<0><1a80ca>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1a814d> DW_AT_stmt_list : 0x8e02a
<1a8151> DW_AT_macro_info : 0xc6fb
<1><1a819b>: Abbrev Number: 3 (DW_TAG_variable)
<1a819c> DW_AT_name : test_inst
<1a81ad> DW_AT_type : <0x1a7643>
<1a81b6> DW_AT_location : 5 byte block: 3 50 6e ff 1f (DW_OP_addr: 1fff6e50)
<1a81bc> Unknown AT value: 2768: 1
<1><1a81e0>: Abbrev Number: 0
Compilation Unit @ offset 0x1a829e:
Length: 0xb8 (32-bit)
Version: 3
Abbrev Offset: 0xd3e6
Pointer Size: 4
<0><1a82a9>: Abbrev Number: 1 (DW_TAG_compile_unit)
<1a832c> DW_AT_stmt_list : 0x8e02a
<1a8330> DW_AT_macro_info : 0xc6fb
<1><1a8334>: Abbrev Number: 3 (DW_TAG_variable)
<1a8335> DW_AT_name : test_sub
<1a834a> DW_AT_type : <0x1a761a>
<1a8352> DW_AT_location : 5 byte block: 3 48 7d ff 1f (DW_OP_addr: 1fff7d48)
<1a8358> Unknown AT value: 2768: 1
<1><1a8359>: Abbrev Number: 0
如您所见,test_inst 位于 0x1fff6e50 地址。而 test_sub 位于 0x1fff6e48。这是对的。如果我们要检查内存,那么:
- test_sub.a 位于 0x1fff6e48
- test_sub.b 位于 0x1fff6e4c
- test_inst.as_ref 应该位于 0x1fff6e50
- test_inst.c 位于 0x1fff6e54
- test_inst.d 位于 0x1fff6e58
我想知道如何手动查找 0x1fff6e48 地址,如果我在 as_ref.
中只有参考main_struct 的矮人信息是这样的:
<1><1a7643>: Abbrev Number: 40 (DW_TAG_structure_type)
<1a7644> DW_AT_sibling : <0x1a76cf>
<1a7648> DW_AT_name : test_struct
<1a7654> DW_AT_byte_size : 44
<2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
<1a7656> DW_AT_type : <0x1a683a>
<1a7658> DW_AT_accessibility: 1 (public)
<1a7659> DW_AT_name : as_ref
<1a7660> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
<2><1a7663>: Abbrev Number: 44 (DW_TAG_member)
<1a7664> DW_AT_type : <0x1a6833>
<1a7666> DW_AT_accessibility: 1 (public)
<1a7667> DW_AT_name : c
<1a7669> DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
<2><1a766c>: Abbrev Number: 44 (DW_TAG_member)
<1a766d> DW_AT_type : <0x1a6833>
<1a766f> DW_AT_accessibility: 1 (public)
<1a7670> DW_AT_name : d
<1a7672> DW_AT_data_member_location: 2 byte block: 23 8 (DW_OP_plus_uconst: 8)
<2><1a76ce>: Abbrev Number: 0
as_ref类型参考这个:
<1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
<1a683b> DW_AT_type : <0x1a761a>
这将被引用:
<1><1a761a>: Abbrev Number: 40 (DW_TAG_structure_type)
<1a761b> DW_AT_sibling : <0x1a7643>
<1a761f> DW_AT_name : sub_struct
<1a762f> DW_AT_byte_size : 8
<2><1a7630>: Abbrev Number: 44 (DW_TAG_member)
<1a7631> DW_AT_type : <0x1a6833>
<1a7633> DW_AT_accessibility: 1 (public)
<1a7634> DW_AT_name : a
<1a7636> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
<2><1a7639>: Abbrev Number: 44 (DW_TAG_member)
<1a763a> DW_AT_type : <0x1a6833>
<1a763c> DW_AT_accessibility: 1 (public)
<1a763d> DW_AT_name : b
<1a763f> DW_AT_data_member_location: 2 byte block: 23 4 (DW_OP_plus_uconst: 4)
<2><1a7642>: Abbrev Number: 0
TLDR:指针和引用在 hookd 下是一样的。 as_ref
包含引用的地址 sub_struct
。
这告诉您 as_ref
位于偏移量 0(因此为 0x1fff6e50):
<2><1a7655>: Abbrev Number: 44 (DW_TAG_member)
<1a7656> DW_AT_type : <0x1a683a>
<1a7658> DW_AT_accessibility: 1 (public)
<1a7659> DW_AT_name : as_ref
<1a7660> DW_AT_data_member_location: 2 byte block: 23 0 (DW_OP_plus_uconst: 0)
其类型为:
<1><1a683a>: Abbrev Number: 5 (DW_TAG_reference_type)
<1a683b> DW_AT_type : <0x1a761a>
这意味着它是对另一种类型的引用。引用和指针在本质上是一样的:它们包含另一个变量的地址。
进程内部:
void* main_struct_addr = 0x1fff6e50; // from DWARF
std::uint64_t as_ref_offset = 0; // from DWARF
void* main_as_ref_addr = (char*) main_struct_addr + as_ref_offset;
void as_addr = *(void**) main_a_ref_addr;
assert(as_adddr == (void*) 0x1fff6e48);
来自另一个进程:
std::uint64_t main_struct_addr = 0x1fff6e50; // from DWARF
std::uint64_t as_ref_offset = 0; // from DWARF
std::uint64_t main_as_ref_addr = main_struct_addr + as_ref_offset;
errno = 0;
void* as_addr = (void*) ptrace(PTRACE_PEEKDATA, pid, (void*) main_as_ref_addr, NULL);
if (errno) { ... }
assert(as_adddr == (void*) 0x1fff6e48);