C 在十六进制文件中我的函数在哪里?
我试图了解更多关于二进制文件的知识。所以我写了一个指针*数据以二进制形式打印出函数。问题是我在hextump文件中找不到打印到stdio的十六进制值C 在十六进制文件中我的函数在哪里?,c,binary,hex,hexdump,C,Binary,Hex,Hexdump,我试图了解更多关于二进制文件的知识。所以我写了一个指针*数据以二进制形式打印出函数。问题是我在hextump文件中找不到打印到stdio的十六进制值 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> /* Our old friend die from ex17. */ void die(const char *message){ i
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* Our old friend die from ex17. */
void die(const char *message){
if(errno){
perror(message);
}
else{
printf("ERROR: %s\n", message);
}
exit(1);
}
// a typedef creates a fake type, in this
// case for a function pointer
typedef int (*compare_cb)(int a, int b);
/* A classic buble sort function that uses
the compare_cb to do the sorting */
int *bubble_sort(int *numbers, int count, compare_cb cmp){
int temp = 0;
int i = 0;
int j = 0;
int *target = malloc(count * sizeof(int));
if(!target) die("Memory error.");
memcpy(target, numbers, count * sizeof(int));
for(i = 0; i < count; i++) {
for(j = 0; j < count - 1; j++) {
if(cmp(target[j], target[j+1])>0) {
temp = target[j+1];
target[j+1] = target[j];
target[j] = temp;
}
}
}
return target;
}
int sorted_order(int a, int b){
return a - b;
}
int reverse_order(int a, int b){
return b - a;
}
int strange_order(int a, int b){
if(a == 0 || b == 0){
return 0;
}
else{
return a % b;
}
}
/* Used to test that we are sorting things correctly by doing the sort and printing it out. */
void test_sorting(int *numbers, int count, compare_cb cmp){
int i = 0;
int *sorted = bubble_sort(numbers, count, cmp);
if(!sorted) die("Failed to sort as requested.");
for(i = 0; i < count; i++) {
printf("%d ", sorted[i]);
}
printf("\n");
free(sorted);
// printing function pointers purposefully
unsigned char *data = (unsigned char *)cmp;
for(i = 0; i < 25; i++) {
printf("%02x:", data[i]);
}
printf("\n");
}
int main(int argc, char *argv[]){
if(argc < 2) die("USAGE: ex18 4 3 1 5 6");
int count = argc - 1;
int i = 0;
char **inputs = argv + 1;
int *numbers = malloc(count * sizeof(int));
if(!numbers) die("Memory error.");
for(i = 0; i < count; i++) {
numbers[i] = atoi(inputs[i]);
}
test_sorting(numbers, count, sorted_order);
test_sorting(numbers, count, reverse_order);
test_sorting(numbers, count, strange_order);
free(numbers);
return 0;
}
我得到:
1 2 3
55:48:89:e5:89:7d:fc:89:75:f8:8b:45:f8:8b:55:fc:29:c2:89:d0:5d:c3:55:48:89:
3 2 1
55:48:89:e5:89:7d:fc:89:75:f8:8b:45:fc:8b:55:f8:29:c2:89:d0:5d:c3:55:48:89:
2 3 1
55:48:89:e5:89:7d:fc:89:75:f8:83:7d:fc:00:74:06:83:7d:f8:00:75:07:b8:00:00:
然后我跑:
$hexdump ex18 > ex18_hexdump
ex18_hexdump中的内容是(根据注释使用正确的文件进行更新,由于帖子的限制而被截断):
我找不到55和48紧挨着
更新1:更新后的二进制文件具有以下模式,与我打印的函数类似:
第一种模式:
0000790 7be9 ffff 0fff 001f 73e9 ffff 55ff 8948
00007a0 48e5 ec83 4810 7d89 e8f8 fe72 ffff 008b
00007b0 c085 0e74 8b48 f845 8948 e8c7 fec0 ffff
第二种模式:
0000980 99fc 7df7 89f8 5dd0 55c3 8948 48e5 ec83
0000990 4840 7d89 89d8 d475 8948 c855 45c7 00ec
00009a0 0000 4800 558b 8bc8 d44d 8b48 d845 ce89
但是,根据我打印出来的图案:
55:48:89:e5:89:7d:fc:89:75:f8:8b:45:f8:8b:55:fc:29:c2:89:d0:5d:c3:55:48:89:
我应该能够在二进制文件中找到这个函数,也就是说,我在二进制文件中查找如下内容:
…89fc7d89e5894855
但上述第一种模式有:
…8348e5894855
这与我所寻找的模式不同
上述第二种模式有:
…8348e5894855
这也是不同的。如果您想知道编译器(或者严格地说是链接器)在二进制文件中的数据和函数的位置,您需要指示链接器生成,或者您可以在现有对象文件上使用和/或实用程序。编译代码后,无需任何优化,我得到了大小为10136字节的可执行文件
ex18
<代码>文件将其报告为“Mach-O 64位可执行x86_64”,因为我在Mac上。系统上的某些工具名称和符号可能不同
让我们用Linux et fili的一些标准工具来看看这个文件
使用hextump
我得到了363行hex,其中一些是*
,表示重复了前一行。(如果没有默认设置,我将得到10136/16=821行。)
添加-Wl,-map,ex18.map
(请记住:我使用的是OS X,此命令行语法不同于gcc常规版本的默认语法)之后,我得到一个以
(__TEXT,__text) section
start:
00000001000007a0 pushq $0x00
00000001000007a2 movq %rsp,%rbp
00000001000007a5 andq $0xf0,%rsp
00000001000007a9 movq 0x08(%rbp),%rdi
00000001000007ad leaq 0x10(%rbp),%rsi
00000001000007b1 movl %edi,%edx
00000001000007b3 addl $0x01,%edx
路径:ex18
#拱门:x86_64
#对象文件:
[0]链接器已合成
[1]/usr/lib/crt1.10.6.o
[2]/var/folders/b6/g3yv219j13v46njdytcd767w0000gn/T//ccoACNzu.o
[3]/usr/lib/libSystem.dylib
#章节:
#地址大小段段
0x1000007A00x0000056F\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
0x100000D10 0x00000036\uuuu文本\uuuu存根
0x100000D48 0x0000006C\uuuuu文本\uuuuu存根\uu帮助程序
0x100000DB4 0x00000056文本字符串
0x100000E0A 0x00000050\uuuu文本\uuuu展开\uu信息
0x100000E60 0x00000198文本框
0x100001000 0x00000028\u数据\u程序\u变量
0x100001028 0x00000010\u数据\u nl\u符号\u ptr
0x100001038 0x00000048_uuuu数据_uuula_u符号_uptr
0x100001080 0x00000020\u数据\u公共
#符号:
#地址大小文件名
0x1000007A00x0000003C[1]启动
0x1000007E0 0x00000050[2]\u模具
0x100008300x000001C0[2]\u气泡\u排序
0x10000009F0 0x00000070[2]\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu内联\u memcpy\u chk
0x10000A60 0x00000020[2]\u排序\u顺序
0x100000A80 0x00000020[2]\u相反顺序
0x100000AA0 0x00000040[2]\u奇怪\u顺序
0x100000AE0 0x00000100[2]\u测试\u排序
0x100000BE0 0x0000012F[2]\u主
。。接下来是程序中使用的更多函数(\u atoi
,\u exit
)和文本字符串的地址等。这些信息告诉我们什么
- 您可以忽略大偏移量
李>0x100000000
- 余数是可执行二进制文件中每个项的偏移量李>
- 大多数名称都添加了一个或多个前导下划线(这是大多数链接器的一个特点,归结起来就是“有一个唯一的名称”——不用担心)李>
- 广义而言,
用于指示文件的每个部分的用途。有些部分是可执行的(在这种情况下,部分
是可执行的);有些包含文本数据(\uu text
仅包含程序中的文本字符串)。出于几个好的原因,可执行文件被划分为多个部分。例如,“代码”只能在可执行部分中运行,“只读数据”可能永远不会执行,以此类推\uu cstring
符号是可执行文件中函数和数据的地址。在这个转储中,地址以最基本的形式出现:减去巨大的常量,作为可执行文件的偏移量
符号
列表,似乎是您感兴趣的地方<例如,代码>开始在我的二进制文件中位于7A0
。检查十六进制转储,我在该位置找到以下字节序列:6A 00 48 89 E5 48 83 E4 F0..
。现在,这些是对CPU的文字指令。我们可以在排序顺序
、反向顺序
和奇怪顺序
中找到相同的字节,并确认它们与从程序“内部”打印时得到的字节几乎相同
但是这些字节意味着什么呢?转到下一个工具
Clifford提到了objdump
,我的OSX有otool
。使用otool-tvex18
,我得到了404行长的文本部分反汇编。拆解从以下步骤开始:
(__TEXT,__text) section
start:
00000001000007a0 pushq $0x00
00000001000007a2 movq %rsp,%rbp
00000001000007a5 andq $0xf0,%rsp
00000001000007a9 movq 0x08(%rbp),%rdi
00000001000007ad leaq 0x10(%rbp),%rsi
00000001000007b1 movl %edi,%edx
00000001000007b3 addl $0x01,%edx
这是我上面展示的十六进制字节的写出形式(“反汇编”)otool
包含非常有用的函数名作为标签,因此我们可以滚动列表,再次找到您的\u排序顺序
、\u反向顺序
和\u奇怪顺序
函数。以下是我得到的:
55 48 89 E5 89 7D FC 89 75 F8 ...
或者,在更可读的反汇编中:
_sorted_order:
0000000100000a60 pushq %rbp
0000000100000a61 movq %rsp,%rbp
0000000100000a64 movl %edi,0xfc(%rbp)
0000000100000a67 movl %esi,0xf8(%rbp)
0000000100000a6a movl 0xfc(%rbp),%eax
0000000100000a6d movl 0xf8(%rbp),%ecx
0000000100000a70 subl %ecx,%eax
0000000100000a72 movl %eax,0xf0(%rbp)
0000000100000a75 movl 0xf0(%rbp),%eax
0000000100000a78 movl %eax,0xf4(%rbp)
0000000100000a7b movl 0xf4(%rbp),%eax
0000000100000a7e popq %rbp
0000000100000a7f ret
关于这一点的确切含义,您可能需要查阅汇编程序网站。组装可能看起来很吓人,但即使是一本简短的入门读物也足以理解一般要点。我,我能像读小说一样读这本书(又短又无聊);)
它从内部堆栈中读取两个值,从另一个值中减去一个值,然后在%eax
中返回该值。看起来差不多是什么
_sorted_order:
0000000100000a60 pushq %rbp
0000000100000a61 movq %rsp,%rbp
0000000100000a64 movl %edi,0xfc(%rbp)
0000000100000a67 movl %esi,0xf8(%rbp)
0000000100000a6a movl 0xfc(%rbp),%eax
0000000100000a6d movl 0xf8(%rbp),%ecx
0000000100000a70 subl %ecx,%eax
0000000100000a72 movl %eax,0xf0(%rbp)
0000000100000a75 movl 0xf0(%rbp),%eax
0000000100000a78 movl %eax,0xf4(%rbp)
0000000100000a7b movl 0xf4(%rbp),%eax
0000000100000a7e popq %rbp
0000000100000a7f ret
test_sorting (numbers, count, sorted_order);
unsigned char *data = (unsigned char *)test_sorting;
for(i = 0; i < 25; i++) {
printf("%02x:", data[i]);
}
printf("\n");
0x100000DB4 0x0000000B [ 2] literal string: ERROR: %s