如何将包含 32 位 asm 的 C 程序编译成 .o 文件?

How to Compile a C program which contains 32bit asm into .o file?

简介

我正在阅读“学习Linux二进制分析”一书。我有一些使用 32 位汇编和 C 的经验(但仍然认为自己是新手)。然而,我在如何编译一个包含 32 位程序集的 c 程序到目标文件 .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 [=10=]x80\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”标志。我猜哪个是问题所在?但是不完全确定,如果是这样的话,不知道如何用 C 和 gcc 在 32 位中编译它?

我还尝试将其更改为 64 位以查看它是否有效,方法是将每个命令的 'l' 替换为 'q' 并将寄存器更改为以 'r' 开头。这似乎有效。但是这本书使用 32 位。所以我希望保持这种状态。有任何想法吗?抱歉,如果这是一个非常基本的问题。

也试过“-m32”但收到这个:

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

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

您收到该错误是因为您没有安装 32 位库。

如果使用 Ubuntu:

sudo apt-get install gcc-multilib

如今,针对 32 位 x86 的知识用处有限,因为基本上每个人都已切换到 64 位(这是一件好事 - 32 位有很多寄存器压力和地址 space压力)。

幸运的是,您实际上不需要任何 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),那么在汇编中实现单个功能仍然比编写汇编 everywhere.

容易得多