2017-09-13 57 views
1

介紹如何編譯包含32位asm的C程序到.o文件中?

我通過這本書 「學習Linux二進制分析」 以下。我有一些使用32位程序集和C的經驗(但仍然認爲自己是新手)。然而,我有麻煩和混淆如何編譯一個C程序,其中包含32位程序集到一個對象文件.o。所以即時猜測這只是我的一個編譯問題。

源代碼用於基於代碼注入的二進制修補的一個示例的一部分。

源代碼

#include <sys/syscall.h> 
int _write (int fd, void *buf, int count) 
{ 
    long ret; 
    __asm__ __volatile__ ("pushl %%ebx\n\t" 
    "movl %%esi,%%ebx\n\t" 
    "int $0x80\n\t""popl %%ebx":"=a" (ret) 
          :"0" (SYS_write), "S" ((long) fd), 
    "c" ((long) buf), "d" ((long) count)); 
    if (ret >= 0) { 
     return (int) ret; 
} 
return -1; 
} 
int evil_puts(void) 
{ 
     _write(1, "HAHA puts() has been hijacked!\n", 31); 
} 

問題

我嘗試編譯evil_puts.c成的.o文件。隨後將用於注入另一個簡單的程序。

gcc -c evil_puts.c 

evil_puts.c: Assembler messages:

evil_puts.c:5: Error: invalid instruction suffix for `push'

evil_puts.c:8: Error: invalid instruction suffix for `pop'

我曾與32位彙編燃氣工作時之前收到此。爲了解決這個問題,我在編譯和鏈接時加上'-32'標誌。我猜是哪個問題?但是不完全確定,並且沒有關於如何在32位使用C和gcc編譯它的想法(如果是這種情況)?

我也試圖將它更改爲64位,看看它是否會工作,將'l'的每個命令替換爲'q'並將寄存器更改爲'r'。這似乎工作。但是這本書使用32位。所以我想保持這樣。有任何想法嗎?對不起,如果這是一個非常基本的問題。

也試過「-m32」,但收到此:

fatal error: sys/syscall.h: No such file or directory

+1

我想你應該使用**'-m32' ...** –

+1

在剛剛學習時不要將32b更改爲64b,它通常需要比替換寄存器更多的努力,在這種特殊情況下,不應在64b中使用「int 0x80」,並且沒有簡單的替換。正確的'syscall'可以代替'int 0x80',但它會有不同的參數,所以你仍然需要重寫所有的參數。因此,您使用32b二進制文件跟蹤本書的努力是一個很好的決定,移植32b到64b目標平臺需要相當多的經驗和時間。 – Ped7g

+0

@ Ped7g:同樣重要的是,您不能在64位代碼中安全地從內聯asm中'push'/'pop',因爲這會破壞紅區。 https://stackoverflow.com/questions/34520013/using-base-pointer-register-in-c-inline-asm。對於64位模式下的「int $ 0x80」,請參閱https://stackoverflow.com/questions/46087730/what-happens-if-you-use-the-32-bit-int-0x80-linux-abi-in -64位碼 –

回答

3

使用gcc -m32 -c evil_puts.c -o evil_puts.o

你收到這個錯誤,因爲你沒有安裝32位的庫。

如果使用Ubuntu:

sudo apt-get install gcc-multilib

1

知識特定於32位x86用處有限的這些天,因爲基本上大家都已經切換到64位(這是一件好事 - 32位有很多寄存器壓力和地址空間壓力)。

幸運的是,您實際上並不需要任何asm來處理您正在做的事情。我還做了幾個理智修正:

#define _GNU_SOURCE 
#include <string.h> 
#include <unistd.h> 
#include <sys/syscall.h> 

#define write_str(fd, s) my_write(fd, s, strlen(s)) 
static ssize_t my_write(int fd, const void *buf, size_t count) 
{ 
    return syscall(SYS_write, (long)fd, (long)buf, (long)count); 
} 

int puts(const char *s __attribute__((unused))) 
{ 
    write_str(STDOUT_FILENO, "HAHA puts() has been hijacked!\n"); 
    return strlen(s) + 1; 
} 

我不知道到底爲什麼你避免write(2)。但是,如果你真的需要避免syscall(2),那麼在裝配中實現該單一功能仍然要比編寫組裝無處不在要容易得多。

相關問題