欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MessageBox()--shellcode(二)

程序员文章站 2022-07-15 14:46:24
...

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;
}
反汇编总体:

MessageBox()--shellcode(二)
由上可发现,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入栈前,如下图:
MessageBox()--shellcode(二)
执行完第一次入栈 “ push 5 ” 后,ESP = ESP - 4 = 0012FF24
MessageBox()--shellcode(二)
执行所以push语句,即在执行call之前。

		push 5		;5 = SW_SHOW
		push ebx
		mov eax, code
		push eax
		call dword ptr [WinExec]

ESP = 0012FF1C
MessageBox()--shellcode(二)
接下来开始执行call 调用函数,ESP = 0012FF24,与执行完第一个push语句一样,因此我们可以发现,winexec()函数又两个参数,而call执行winexec()函数时,清理堆栈且刚好将两个元素清理出了堆栈,即esp+8,但是我们之前有三个push语句,即esp -12,而 -12 + 8 = -4,因此esp还需要 +4,所以在最后平衡堆栈的时候我们只需要让 esp + 4 即可,即 add esp, 4
MessageBox()--shellcode(二)

方法二: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;
}
相关标签: # 汇编