MessageBox()--shellcode(二)
shellcode 的提取:
参考链接:https://www.cnblogs.com/manu18/articles/9445130.html
理解:指一组计算机能直接执行(不需要点击和编译),实现我们想要功能的机器代码,通常以十六进制数组的形式存在。
(1)、弹出MessageBox()
源代码1:
// 2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "windows.h"
char shellcode[]="\x90\x90\x90\x33\xDB\x53\x68\x64\x63\x62\x61\x68\x68\x67\x66\x65\x8B\xC4\x53\x50\x50\x53\xB8\xEA\x07\xD5\x77\xFF\xD0";
int main(int argc, char* argv[])
{
printf("begin\n");
HINSTANCE libHandle;
char *dll="user32.dll";
libHandle=LoadLibrary(dll);
/*
__asm
{
sub sp,0x454
xor ebx,ebx
push ebx
push 0x61626364
push 0x65666768
mov eax,esp
push ebx
push eax
push eax
push ebx
mov eax,0x77d507ea
call eax
}
*/
__asm
{
lea eax,shellcode
push eax
ret
}
return 0;
}
代码解析:
sub sp, 0x454
给栈区分配一段空间
xor ebx, ebx
将ebx清零
push ebx ;esp-4,作为字符串的的最后一个‘\0’字符
push 0x61626364 ;元素入栈“abcdefgh”
push 0x65666768
mov eax,esp ;将栈顶指针赋值给eax
push ebx ;元素入栈,实现MessageBox()的功能
push eax
push eax
push ebx
mov eax,0x77d507ea
call eax
实验MessageBox()功能。然后反汇编,将机器码保存,每个机器码前面加上‘\x’ 代表十六进制。
源代码2:
这个用的是另外一种调用函数messagebox()的方法,不需要确定他在计算机中的地址,而是通过messagebox在动态链接库user.dll中的内存基址来进行调用。
// test0218——5.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
printf("Hello World!\n");
LoadLibraryA("user32.dll"); //载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源
HMODULE hmd=GetModuleHandleW(L"user32.dll"); //hmd就是user32.dll在这个实例的内存基址
ULONG addr=(ULONG)GetProcAddress(hmd,"MessageBoxA"); //hmd就是user32.dll在这个实例的内存基址
char* aa="这是内联汇编,哈哈!";
char* bb="提示"; //aa bb是2个字符串的首地址
//MessageBoxA(0,aa,bb,MB_OK|MB_ICONINFORMATION); //如果取消屏蔽你会看到一模一样的弹框
__asm
{
push 0x40 //最后一个参数
mov eax,bb //标题
push eax
mov eax,aa //内容
push eax
push 0 //句柄
mov eax,addr //messagebox的地址,我们不能直接call addr要给他放一个寄存器里面再call寄存器这样一个过程就完成了
call eax //call这个地址
}
system("pause");
return 0;
}
(2)、弹出cmd程序
拓展:
HINSTANCE 是“句柄型”数据类型。相当于装入到了内存的资源的ID。HINSTANCE对应的资源是instance.句柄实际上是一个
无符号长整数。 Handle 是代表系统的内核对象,如文件句柄,线程句柄,进程句柄。 HMODULE
是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。 HINSTANCE
在win32下与HMODULE是相同的东西,在Win32下还存在主要是因为win16程序使用HINSTANCE来区别task。
winexec函数
这个函数和system()非常类似,只能运行.EXE文件,这样在WINDOWS中有它不尽人意的地方,比如不能用此方法通过关联的方法打开文件,例如WinExec(“1.html”,SW_SHOWNA);就不能打开此文档
WinExec() 函数原型:
UINT WinExec(LPCSTR lpCmdLine,UINT uCmdShow);
参数说明:(**的意思是能接受焦点,即标题栏变成蓝色)
lpCmdLine:以0结尾的字符串,命令行参数。
uCmdShow:新的应用程序的运行方式。取值如下:
SW_HIDE 隐藏
SW_MAXIMIZE 最大化
SW_MINIMIZE 最小化,并把Z order顺序在此窗口之后(即窗口下一层)的窗口**
SW_RESTORE **窗口并还原为初始化大小 SW_SHOW 以当前大小和状态**窗口
SW_SHOWDEFAULT 以默认方式运行
SW_SHOWMAXIMIZED **窗口并最大化
SW_SHOWMINIMIZED **窗口并最小化
SW_SHOWMINNOACTIVE 最小化但不改变当前**的窗口
SW_SHOWNA 以当前状态显示窗口但不改变当前**的窗口
SW_SHOWNOACTIVATE 以初始化大小显示窗口但不改变当前**的窗口
SW_SHOWNORMAL **并显示窗口,如果是最大(小)化,窗口将会还原。第一次运行程序 时应该使用这个值
比如说,我想要用记事本打开"C:\HDC.TXT",以正常方式运行:
WinExec(“notepad c:\hdc.txt”,SW_SHOWNORMAL);
如果调用成功,这个函数会返回一个不小于31的值,否则调用失败,其返回值的意义如下:
0 系统内存或资源不足
ERROR_BAD_FORMAT .EXE文件格式无效(比如不是32位应用程序)
ERROR_FILE_NOT_FOUND 指定的文件设有找到
ERROR_PATH_NOT_FOUND 指定的路径没有找到
弹出cmd.exe程序:
C语言代码:
#include "stdafx.h"
#include<windows.h>
int main(int argc, char* argv[])
{
printf("Hello World!\n");
HINSTANCE libHandle;
char* dll = "kernel32.dll";
libHandle = LoadLibrary(dll);
//载入指定的动态链接库,并将它映射到当前进程使用的地址空间。一旦载入,即可访问库内保存的资源
WinExec("cmd.exe",SW_SHOW);
return 0;
}
反汇编总体:
由上可发现,WinExec函数的执行类似与MessageBox()函数,即先将参数倒序push入栈,然后再利用 call 指令调用api
13: WinExec("cmd.exe",SW_SHOW);
00401052 8B F4 mov esi,esp
00401054 6A 05 push 5
00401056 68 1C 20 42 00 push offset string "cmd.exe" (0042201c)
0040105B FF 15 4C A1 42 00 call dword ptr [__imp__WinExec@8 (0042a14c)]
00401061 3B F4 cmp esi,esp
00401063 E8 C8 00 00 00 call __chkesp (00401130)
以上为Winexec()函数的具体实现。
汇编代码:
方法一:add esp,4平衡堆栈
int main(int argc, char* argv[])
{
printf("Hello World!\n");
HINSTANCE libHandle;
char* dll = "kernel32.dll";
libHandle = LoadLibrary(dll);
// WinExec("cmd.exe",SW_SHOW);
char* code="cmd.exe";
_asm{
xor ebx, ebx
push 5 ;5 = SW_SHOW
push ebx
mov eax, code
push eax
call dword ptr [WinExec]
add esp,4 ;堆栈平衡了
}
return 0;
}
在此,我们运用“add asp 4”,进行堆栈的平衡。然后
原理:
首先push入栈前,如下图:
执行完第一次入栈 “ push 5 ” 后,ESP = ESP - 4 = 0012FF24
执行所以push语句,即在执行call之前。
push 5 ;5 = SW_SHOW
push ebx
mov eax, code
push eax
call dword ptr [WinExec]
ESP = 0012FF1C
接下来开始执行call 调用函数,ESP = 0012FF24,与执行完第一个push语句一样,因此我们可以发现,winexec()函数又两个参数,而call执行winexec()函数时,清理堆栈且刚好将两个元素清理出了堆栈,即esp+8,但是我们之前有三个push语句,即esp -12,而 -12 + 8 = -4,因此esp还需要 +4,所以在最后平衡堆栈的时候我们只需要让 esp + 4 即可,即 add esp, 4
方法二:mov esp,0x450找到原来的位置清理堆栈
这个是之前学长的,怎么说呢,我的理解是它主要找到 esp 原来的位置,然后用 mov 指令直接将原来的 esp 地址赋值给esp,但是这个随机性可能有点大,并且在不同的计算机运行地址可能不一样,因此。。。。
参考链接:https://blog.csdn.net/qq_41683305/article/details/104236403
#include "stdio.h"
#include "windows.h"
{
printf("begin\n");
HINSTANCE libHandle;
char *dll="kernel32.dll";
libHandle=LoadLibrary(dll);
char *str="cmd.exe";
//WinExec("cmd.exe",SW_SHOW);
__asm{
sub esp,0x454
xor ebx,ebx
push ebx
mov eax,str
push 5 ;5=SW_SHOW
push eax
call dword ptr [WinExec]
mov esp,0x450
}
return 0;
}
上一篇: 【dubbo】分布式服务框架の简单认识