ctypes的:铸铁字符串函数? [英] ctypes: Cast string to function?

查看:137
本文介绍了ctypes的:铸铁字符串函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在阅​​读文章<一个href=\"http://pen-testing.sans.org/blog/pen-testing/2011/10/13/tips-for-evading-anti-virus-during-pen-testing\"相对=nofollow>逃避反病毒软件的提示在渗透测试,被赋予Python程序一惊:

I was reading the article Tips for Evading Anti-Virus During Pen Testing and was surprised by given Python program:

from ctypes import *
shellcode = '\xfc\xe8\x89\x00\x00....'

memorywithshell = create_string_buffer(shellcode, len(shellcode))
shell = cast(memorywithshell, CFUNCTYPE(c_void_p))
shell()

外壳code缩短。有人能解释这是怎么回事?我熟悉Python和C,我试着读了 ctypes的 模块,但也有留下了两个主要问题:

The shellcode is shortened. Can someone explain what is going on? I'm familiar with both Python and C, I've tried read on the ctypes module, but there are two main questions left:


  • 什么是存储在壳code ?结果
    我知道这具有的的东西的用C做(在文章中是从Metasploit工具的外壳code和ASCII不同的符号被选择),但我不能确定是否如果是C源(可能没有)或者从某种汇编的起源(它?)。

  • What is stored in shellcode?
    I know this has something to do with C (in the article it is an shellcode from Metasploit and a different notation for ASCII was chosen), but I cannot identify whether if it's C source (probably not) or originates from some sort of compilation (which?).

根据第一个问题,什么是魔法的施法过程中发生了什么?

Depending on the first question, what's the magic happening during the cast?

推荐答案

看一看这个壳code,我托克它的这里(它会弹出一个MessageBoxA):

Have a look at this shellcode, I toke it from here (it pops up a MessageBoxA):

#include <stdio.h>

typedef void (* function_t)(void);

unsigned char shellcode[] =
    "\xFC\x33\xD2\xB2\x30\x64\xFF\x32\x5A\x8B"
    "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x33\xC9"
    "\xB1\x18\x33\xFF\x33\xC0\xAC\x3C\x61\x7C"
    "\x02\x2C\x20\xC1\xCF\x0D\x03\xF8\xE2\xF0"
    "\x81\xFF\x5B\xBC\x4A\x6A\x8B\x5A\x10\x8B"
    "\x12\x75\xDA\x8B\x53\x3C\x03\xD3\xFF\x72"
    "\x34\x8B\x52\x78\x03\xD3\x8B\x72\x20\x03"
    "\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47"
    "\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F"
    "\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72"
    "\x65\x75\xE2\x49\x8B\x72\x24\x03\xF3\x66"
    "\x8B\x0C\x4E\x8B\x72\x1C\x03\xF3\x8B\x14"
    "\x8E\x03\xD3\x52\x33\xFF\x57\x68\x61\x72"
    "\x79\x41\x68\x4C\x69\x62\x72\x68\x4C\x6F"
    "\x61\x64\x54\x53\xFF\xD2\x68\x33\x32\x01"
    "\x01\x66\x89\x7C\x24\x02\x68\x75\x73\x65"
    "\x72\x54\xFF\xD0\x68\x6F\x78\x41\x01\x8B"
    "\xDF\x88\x5C\x24\x03\x68\x61\x67\x65\x42"
    "\x68\x4D\x65\x73\x73\x54\x50\xFF\x54\x24"
    "\x2C\x57\x68\x4F\x5F\x6F\x21\x8B\xDC\x57"
    "\x53\x53\x57\xFF\xD0\x68\x65\x73\x73\x01"
    "\x8B\xDF\x88\x5C\x24\x03\x68\x50\x72\x6F"
    "\x63\x68\x45\x78\x69\x74\x54\xFF\x74\x24"
    "\x40\xFF\x54\x24\x40\x57\xFF\xD0";

void real_function(void) {
    puts("I'm here");
}

int main(int argc, char **argv)
{
    function_t function = (function_t) &shellcode[0];

    real_function();
    function();
    return 0;
}

编译成为一个钩子任何调试器下,我将使用gdb的:

Compile it an hook it under any debugger, I'll use gdb:

> gcc shellcode.c -o shellcode
> gdb -q shellcode.exe
Reading symbols from shellcode.exe...done.
(gdb)
>

拆卸main函数调用看到之间的不同 real_function 函数

(gdb) disassemble main
Dump of assembler code for function main:
   0x004013a0 <+0>:     push   %ebp
   0x004013a1 <+1>:     mov    %esp,%ebp
   0x004013a3 <+3>:     and    $0xfffffff0,%esp
   0x004013a6 <+6>:     sub    $0x10,%esp
   0x004013a9 <+9>:     call   0x4018e4 <__main>
   0x004013ae <+14>:    movl   $0x402000,0xc(%esp)
   0x004013b6 <+22>:    call   0x40138c <real_function> ; <- here we call our `real_function`
   0x004013bb <+27>:    mov    0xc(%esp),%eax
   0x004013bf <+31>:    call   *%eax                    ; <- here we call the address that is loaded in eax (the address of the beginning of our shellcode)
   0x004013c1 <+33>:    mov    $0x0,%eax
   0x004013c6 <+38>:    leave
   0x004013c7 <+39>:    ret
End of assembler dump.
(gdb)

有两个呼叫,让我们做一个破发点位于&lt;主+ 31&GT; 来看看什么是加载EAX:

There are two call, let's make a break point at <main+31> to see what is loaded in eax:

(gdb) break *(main+31)
Breakpoint 1 at 0x4013bf
(gdb) run
Starting program: shellcode.exe
[New Thread 2856.0xb24]
I'm here

Breakpoint 1, 0x004013bf in main ()
(gdb) disassemble
Dump of assembler code for function main:
   0x004013a0 <+0>:     push   %ebp
   0x004013a1 <+1>:     mov    %esp,%ebp
   0x004013a3 <+3>:     and    $0xfffffff0,%esp
   0x004013a6 <+6>:     sub    $0x10,%esp
   0x004013a9 <+9>:     call   0x4018e4 <__main>
   0x004013ae <+14>:    movl   $0x402000,0xc(%esp)
   0x004013b6 <+22>:    call   0x40138c <real_function>
   0x004013bb <+27>:    mov    0xc(%esp),%eax
=> 0x004013bf <+31>:    call   *%eax                    ; now we are here
   0x004013c1 <+33>:    mov    $0x0,%eax
   0x004013c6 <+38>:    leave
   0x004013c7 <+39>:    ret
End of assembler dump.
(gdb)

看前3个字节数据,在EAX地址继续说道:

Look at the first 3 bytes of the data that the address in eax continues:

(gdb) x/3x $eax
0x402000 <shellcode>:   0xfc    0x33    0xd2
(gdb)                    ^-------^--------^---- the first 3 bytes of the shellcode

因此​​CPU将呼叫0x402000 ,我们壳code在 0x402000 开始,让拆机在什么都 0x402000

So the CPU will call 0x402000, the beginning of our shell code at 0x402000, lets disassemble what ever at 0x402000:

(gdb) disassemble 0x402000
Dump of assembler code for function shellcode:
   0x00402000 <+0>:     cld
   0x00402001 <+1>:     xor    %edx,%edx
   0x00402003 <+3>:     mov    $0x30,%dl
   0x00402005 <+5>:     pushl  %fs:(%edx)
   0x00402008 <+8>:     pop    %edx
   0x00402009 <+9>:     mov    0xc(%edx),%edx
   0x0040200c <+12>:    mov    0x14(%edx),%edx
   0x0040200f <+15>:    mov    0x28(%edx),%esi
   0x00402012 <+18>:    xor    %ecx,%ecx
   0x00402014 <+20>:    mov    $0x18,%cl
   0x00402016 <+22>:    xor    %edi,%edi
   0x00402018 <+24>:    xor    %eax,%eax
   0x0040201a <+26>:    lods   %ds:(%esi),%al
   0x0040201b <+27>:    cmp    $0x61,%al
   0x0040201d <+29>:    jl     0x402021 <shellcode+33>
   ....

正如你所见,一个shell code无非就是汇编指令多,唯一不同的是,在你写的这些指令的方式,它采用特殊的技术,使其更便携,例如从不使用固定地址。

As you see, a shellcode is nothing more than assembly instructions, the only different is in the way you write these instructions, it uses special techniques to make it more portable, for example never use a fixed address.

蟒蛇相当于上面的程序:

The python equivalent to the above program:

#!python

from ctypes import *

shellcode_data = "\
\xFC\x33\xD2\xB2\x30\x64\xFF\x32\x5A\x8B\
\x52\x0C\x8B\x52\x14\x8B\x72\x28\x33\xC9\
\xB1\x18\x33\xFF\x33\xC0\xAC\x3C\x61\x7C\
\x02\x2C\x20\xC1\xCF\x0D\x03\xF8\xE2\xF0\
\x81\xFF\x5B\xBC\x4A\x6A\x8B\x5A\x10\x8B\
\x12\x75\xDA\x8B\x53\x3C\x03\xD3\xFF\x72\
\x34\x8B\x52\x78\x03\xD3\x8B\x72\x20\x03\
\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47\
\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F\
\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72\
\x65\x75\xE2\x49\x8B\x72\x24\x03\xF3\x66\
\x8B\x0C\x4E\x8B\x72\x1C\x03\xF3\x8B\x14\
\x8E\x03\xD3\x52\x33\xFF\x57\x68\x61\x72\
\x79\x41\x68\x4C\x69\x62\x72\x68\x4C\x6F\
\x61\x64\x54\x53\xFF\xD2\x68\x33\x32\x01\
\x01\x66\x89\x7C\x24\x02\x68\x75\x73\x65\
\x72\x54\xFF\xD0\x68\x6F\x78\x41\x01\x8B\
\xDF\x88\x5C\x24\x03\x68\x61\x67\x65\x42\
\x68\x4D\x65\x73\x73\x54\x50\xFF\x54\x24\
\x2C\x57\x68\x4F\x5F\x6F\x21\x8B\xDC\x57\
\x53\x53\x57\xFF\xD0\x68\x65\x73\x73\x01\
\x8B\xDF\x88\x5C\x24\x03\x68\x50\x72\x6F\
\x63\x68\x45\x78\x69\x74\x54\xFF\x74\x24\
\x40\xFF\x54\x24\x40\x57\xFF\xD0"

shellcode = c_char_p(shellcode_data)

function = cast(shellcode, CFUNCTYPE(None))
function()

这篇关于ctypes的:铸铁字符串函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆