如何在正确提供 argc、argv、envp 的 NASM 中调用用 C 编写的链接可执行文件中的主函数

How to call a main function in a linked executable written in C from NASM with argc,argv,envp supplied correctly

我正在将 C 程序链接到 NASM 可执行文件。汇编文件调用链接C程序中的main函数

virus:  infect.c virus.o
    $(CC) $(LFLAGS) $^ -o $@

virus.o: virus.asm template.asm.inc
    $(ASM) $(AFLAGS) $< -o $@

我尝试了什么:

infect.c 以这种方式包含主要功能:

int main(int argc, char *const argv[], char *const envp[]) {
    DIR *dir;
    struct dirent *ent;
    struct stat st;
    int vfd, xfd, magic;
    pid_t pid;
    off_t offset;
    ino_t inode;

    vfd = open(argv[0], O_RDONLY);
    ...

因为我想从virus.asm调用infect.c中的main函数。主要功能应该 infactvirus.asm 中,因为在可执行文件中不能有两个主要功能,我将 infect.c 中的 main 功能更改为

int infect(int argc, char *const argv[], char *const envp[]) {
    DIR *dir;
    struct dirent *ent;
    struct stat st;
    int vfd, xfd, magic;
    pid_t pid;
    off_t offset;
    ino_t inode;

    vfd = open(argv[0], O_RDONLY);
    ...

1) 我不知道如何从 NASM 程序集调用这个 infact 函数,这是我在 virus.asm 文件

中尝试的
extern infect
main:
    call infect

程序运行,但没有产生预期的效果。 infect.c 是一种 ELF 病毒,应该在 CWD 中寻找文件并感染它们。

2) 问题似乎是我在调用

时没有正确处理 int argc, char *const argv[], char *const envp[]

如何使用提供的 argcargvenvpvirus.asm 正确调用 infect.c 中的函数,以便程序能够工作正常吗?

您可以在 asm 文件中提供 _start 入口点。下面是在 AMD64 和 linux 内核上为 elf abi 设置 argc、argv 和 envp 的示例代码。它不适用于真实代码,因为它不执行通常的初始化过程,例如为 tls 设置 fs 段、初始化静态变量等...但它让您初步了解需要完成的工作!

备忘录 [argc -> %rdi ; argv -> %rsi ;环境 -> %rdx ]

.global _start
.type _start,@function
.align 16
_start:
    .cfi_startproc
    .cfi_undefined rip
/*nullify rbp as required by doc*/
    xor %rbp, %rbp
/*move argc to rdi and advance rsp*/
    popq %rdi
/*set argv*/
    movq %rsp, %rsi
/*now envp is at rsp+8*argc+8*/
    lea 8(%rsp, %rdi, 8), %rdx
/*realign stack*/
  push %rdi
/*push rsp to the stack*/
  callq main
/*call _exit at return*/
  movq %rax,%rdi
  mov 1, %rax
  syscall
  .cfi_endproc
_start:
    xor rbp, rbp
    pop rdi
    mov rsi, rsp
    lea rdx, [rsp+rdi+8*8]
    push rdi
    call main
    mov rdi, rax
    mov eax, 1
    int 80h

在 _start 函数中执行第一件事。如果您需要稍后执行,请确保保存以下寄存器

; save initial program state
mov rbx, rsp 
mov r14, rdi
mov r15, rsi

然后就可以重新加载这些寄存器,调用上面的指令调用main