按照this指令,我设法只产生528字节的大小a.out(当gcc main.c最初给我8539字节的大文件时)。
main.c是:
int main(int argc, char** argv) {
return 42;
}
但我已经从这个汇编文件中构建了一个a.out:
电源:
; tiny.asm
BITS 64
GLOBAL _start
SECTION .text
_start:
mov eax, 1
mov ebx, 42
int 0x80
有:
me@comp# nasm -f elf64 tiny.s
me@comp# gcc -Wall -s -nostartfiles -nostdlib tiny.o
me@comp# ./a.out ; echo $?
42
me@comp# wc -c a.out
528 a.out
因为我需要机器码:
objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .text:
00000000004000e0 <.text>:
4000e0: b8 01 00 00 00 mov $0x1,%eax
4000e5: bb 2a 00 00 00 mov $0x2a,%ebx
4000ea: cd 80 int $0x80
># objdump -hrt a.out
a.out: file format elf64-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .note.gnu.build-id 00000024 00000000004000b0 00000000004000b0 000000b0 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 0000000c 00000000004000e0 00000000004000e0 000000e0 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
SYMBOL TABLE:
no symbols
文件是小端约定:
me@comp# readelf -a a.out
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4000e0
Start of program headers: 64 (bytes into file)
Start of section headers: 272 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 4
Section header string table index: 3
现在我想这样执行:
#include <unistd.h>
// which version is (more) correct?
// this might be related to endiannes (???)
char code[] = "\x01\xb8\x00\x00\xbb\x00\x00\x2a\x00\x00\x80\xcd\x00";
char code_v1[] = "\xb8\x01\x00\x00\x00\xbb\x2a\x00\x00\x00\xcd\x80\x00";
int main(int argc, char **argv)
{
/*creating a function pointer*/
int (*func)();
func = (int (*)()) code;
(int)(*func)();
return 0;
}
但是我得到了分段错误。我的问题是:这部分文字
4000e0: b8 01 00 00 00 mov $0x1,%eax
4000e5: bb 2a 00 00 00 mov $0x2a,%ebx
4000ea: cd 80 int $0x80
(这个机器代码)我真的需要什么?我做错了什么(endianness ??),也许我只需要从SIGSEGV以不同的方式调用它?
代码必须位于具有执行权限的页面中。默认情况下,出于安全原因,堆栈和读写静态数据(如非const全局变量)在没有exec权限的情况下映射到页面中。
最简单的方法是使用gcc -z execstack
进行编译,malloc
链接您的程序,使得堆栈和全局变量(静态存储)在可执行页面中映射,以及使用#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48,
0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00};
/*
00000000004004b4 <main> 55 push %rbp
00000000004004b5 <main+0x1> 48 89 e5 mov %rsp,%rbp
00000000004004b8 <main+0x4> 89 7d fc mov %edi,-0x4(%rbp)
00000000004004bb <main+0x7> 48 89 75 f0 mov %rsi,-0x10(%rbp)
'return 42;'
00000000004004bf <main+0xb> b8 2a 00 00 00 mov $0x2a,%eax
'}'
00000000004004c4 <main+0x10> c9 leaveq
00000000004004c5 <main+0x11> c3 retq
*/
int main(int argc, char **argv) {
void *buf;
/* copy code to executable buffer */
buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANON,-1,0);
memcpy (buf, code, sizeof(code));
__builtin___clear_cache(buf, buf+sizeof(code)-1); // on x86 this just stops memcpy from optimizing away as a dead store
/* run code */
int i = ((int (*) (void))buf)();
printf("get this done. returned: %d", i);
return 0;
}
进行分配。
另一种不使所有内容可执行的方法是将此二进制机器代码复制到可执行缓冲区中。
__builtin___clear_cache
输出:
完成这件事。返回:42
RUN SUCCESSFUL(总时间:57ms)
没有this could break,memcpy
启用了优化,因为gcc会认为__builtin___clear_cache
是一个死的存储并将其优化掉。在编译x86时,the gcc manual实际上并没有清除任何缓存;没有额外的指示;它只是将内存标记为“已使用”,因此它的存储不会被视为“死”。 (见mprotect
。)
另一个选择是char code[]
包含PROT_READ|PROT_WRITE|PROT_EXEC
数组的页面,给它.data
。这适用于它是一个本地数组(在堆栈上)还是const char code[]
中的全局数组。
或者,如果它是.rodata
部分的PROT_READ|PROT_EXEC
,你可以给它ld
。
(在大约2019年之前的binutils .rodata
版本中,.text
被链接为ld
的同一段的一部分,并且已经映射了可执行文件。但是最近的const char code[]
给它一个单独的段,因此它可以在没有exec权限的情况下进行映射,因此void main(){
int i = 11;
//The following is the method to generate the machine code directly!
//mov eax, 1; ret;
const char *code = "\xB8\x10\x00\x00\x00\xc3";
__asm call code; //test successful~..vs 2017
__asm mov i ,eax;
printf("i=%d", i);
}
不会t再给你一个可执行的数组,但过去常常在其他地方给你这个老建议。)
关键是启用了DEP保护!你可以转到配置 - >链接器 - >高级 - > DEP关闭,现在没关系。
qazxswpoi