UPX打包ELF文件中rsp减4096字节的逆向技术问询
问题1:指令
401ddb: and rdx, 0xFFFFFFFFFFFFF000后,循环将rsp减4096直到与rdx相等,此操作的具体作用是什么?0xFFFFFFFFFFFFF000是4096字节(内存页大小)的对齐掩码,执行and rdx, 0xFFFFFFFFFFFFF000会清零rdx的低12位,得到一个页对齐的内存地址。循环将rsp每次减4096直到与该地址相等,本质是强制将当前栈指针对齐到内存页的边界。UPX作为打包器这么做,是因为内存页的权限(可读、可写、可执行)是以页为单位管理的,后续要在栈上开辟用于存放临时数据或解压后代码的区域,必须先让栈指针对齐到页边界,才能让内核正确设置这块内存的页权限。问题2:循环结束后,
0x401e02至0x401e23代码块中sub rsp, rdx的逻辑是什么?
这里的rdx是UPX计算出的、解压过程所需的额外栈空间大小(大概率也是按页大小对齐的数值)。经过前面的循环,rsp已经处于页对齐的地址,此时执行sub rsp, rdx是在该对齐栈的基础上,向低地址方向开辟一块连续的、大小为rdx的栈空间,用来存放解压阶段的临时数据或解压后的代码/数据段,确保这块新开辟的空间也符合页对齐要求,避免因权限设置问题导致执行错误。问题3:
0x401e33处将rsp存入rax再写入[rbp-0x88],该指针指向栈的哪个位置?
rbp是当前函数栈帧的基地址,[rbp-0x88]是栈帧内的一个局部变量存储位置。这里存入的是经过两次调整(页对齐+开辟空间)后的rsp值,也就是当前栈的最顶端(低地址端)位置——因为栈是从高地址向低地址增长的,此时的rsp就是新开辟的页对齐栈区域的起始地址。UPX记录这个地址,主要是为后续往该区域写入解压后的内容、或者在解压完成后恢复栈指针做准备。
内容的提问来源于stack exchange,提问作者Nalan PandiKumar

