x86 32位汇编中execve传递环境变量失效问题排查
问题原因及解决方案
你的问题大概率是环境变量数组(envp)的构造不符合Linux execve系统调用的要求,或者execve的参数传递错误,导致内核无法正确识别你自定义的环境变量。以下是具体原因和修正方法:
常见错误点及修正
1. envp数组未以NULL指针终止
Linux的execve系统调用要求,环境变量数组envp必须是一个以NULL指针结尾的指针数组。如果没有这个终止符,内核无法确定环境变量的结束位置,会直接忽略无效的数组内容,只保留系统默认传递的少量变量(比如PWD)。
2. execve参数传递顺序错误
32位Linux下,execve的系统调用参数约定为:
eax = 59(execve的系统调用号)ebx:指向/bin/sh的路径字符串指针ecx:指向参数数组argv的指针(数组需以NULL结尾)edx:指向环境变量数组envp的指针(数组需以NULL结尾)
如果把envp和argv的传递顺序搞反,shell会把环境变量当成命令参数,自然无法识别为环境变量。
3. 环境变量字符串未以NULL结尾
所有传递给execve的字符串(包括路径、参数、环境变量)必须是C风格的以0字节结尾的字符串。缺少终止符会导致内核解析失败,忽略该变量。
正确的代码示例
以下是能正确传递环境变量的32位x86汇编代码:
section .data ; 定义字符串(均以0结尾) shell_path db '/bin/sh', 0 arg0 db 'sh', 0 ; argv[0],通常是程序名 xca1_str db 'xca1=test_val1', 0 xca2_str db 'xca2=test_val2', 0 xca3_str db 'xca3=test_val3', 0 ; 构造argv数组:指针列表,最后以NULL结尾 argv dd arg0, 0 ; 构造envp数组:指针列表,最后以NULL结尾 envp dd xca1_str, xca2_str, xca3_str, 0 section .text global _start _start: ; 传递execve参数 mov ebx, shell_path ; ebx = 程序路径 mov ecx, argv ; ecx = 参数数组 mov edx, envp ; edx = 环境变量数组 mov eax, 59 ; 32位Linux execve系统调用号 int 0x80 ; 触发系统调用 ; 系统调用失败后的退出逻辑 mov eax, 1 xor ebx, ebx int 0x80
手动构造栈的shellcode场景(无.data段)
如果是编写无数据段的shellcode,需要通过栈来构造argv和envp,注意栈的顺序:
section .text global _start _start: ; 构造envp数组(栈底到栈顶:NULL -> xca3 -> xca2 -> xca1) push 0 ; envp终止符 push 0x3361783d ; "=xca3" (小端序,实际字符串是xca3=xxx) push 0x3376616c ; "lav3" mov eax, esp ; eax指向xca3字符串的起始 push eax push 0x3261783d ; "=xca2" push 0x3276616c ; "lav2" mov eax, esp push eax push 0x3161783d ; "=xca1" push 0x3176616c ; "lav1" mov eax, esp push eax mov edx, esp ; edx = envp数组指针 ; 构造argv数组(栈底到栈顶:NULL -> arg0) push 0 push 0x68732f2f ; "//sh" push 0x6e69622f ; "/bin" mov ebx, esp ; ebx = /bin/sh路径 push ebx ; arg0 = /bin/sh mov ecx, esp ; ecx = argv数组指针 ; 调用execve mov eax, 59 int 0x80
验证方法
编译链接后运行程序,在弹出的shell中执行env命令,应该能看到xca1、xca2、xca3三个变量。如果仍未出现,检查:
- 数组的NULL终止符是否存在
- execve的参数寄存器赋值是否正确
- 字符串的0终止字节是否缺失
内容的提问来源于stack exchange,提问作者Ahmed Tawfik
相关产品推荐
相关产品推荐

