Skip to content

Instantly share code, notes, and snippets.

@juntalis
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juntalis/7b23959196cc756e62e7 to your computer and use it in GitHub Desktop.
Save juntalis/7b23959196cc756e62e7 to your computer and use it in GitHub Desktop.
Using 7 bytes of preassembled shellcode, determine if the current 32-bit process is running in the WOW64 subsystem (as is the case when running 32-bit Python on 64-bit Windows) or if it's running from a 32-bit Windows OS.
# encoding: utf-8
"""
iswow64.py
Using 7 bytes of preassembled shellcode, determine if the current
32-bit process is running in the WOW64 subsystem (as is the case
when running 32-bit Python on 64-bit Windows) or if it's running
from a 32-bit Windows OS.
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
"""
from _ctypes import _SimpleCData as _SimpleCData
from ctypes.wintypes import LPVOID, DWORD, INT, BOOLEAN, HANDLE
from ctypes import WinDLL, POINTER, WinError, c_size_t as SIZE_T, sizeof as SIZEOF, \
cast as CAST, byref as BYREF, create_string_buffer as STRALLOC, \
WINFUNCTYPE as WINAPI, CFUNCTYPE as CDECL
# Verify we're working on a 32-bit version of Python
assert(SIZEOF(LPVOID) == SIZEOF(DWORD))
# Kernel32 DLL
_kernel32 = WinDLL('kernel32.dll')
# Custom Types
class BOOL(INT):
""" Just a 32-bit integer interpreted as a boolean. """
def from_param(self, value):
if value is None:
return INT(0)
elif isinstance(value, _SimpleCData):
return value
else:
return INT(value)
def __eq__(self, other):
value = self.value
if isinstance(other, bool):
return value == other
elif isinstance(other, _SimpleCData):
return value == bool(other.value)
else:
return value == bool(other)
def __hash__(self):
return hash(self._as_parameter_)
# Typedefs
LPCVOID = LPVOID
PDWORD = POINTER(DWORD)
PSIZE_T = POINTER(SIZE_T)
# Constants
NULL = LPVOID(0)
NULL_PDWORD = CAST(NULL, PDWORD)
NULL_PSIZE_T = CAST(NULL, PSIZE_T)
## Param values for flAllocationType & dwFreeType
MEM_RESERVE = DWORD(0x00002000)
MEM_COMMIT = DWORD(0x00001000)
MEM_RELEASE = DWORD(0x8000)
## Param values for flProtect & flNewProtect
PAGE_READWRITE = DWORD(0x04)
PAGE_EXECUTE_READWRITE = DWORD(0x40)
## Param flags Constants
_In = 1
_Out = 2
_InOpt = 3
_InOutOpt = _InOpt | _Out
# Win32 API Function Prototypes
""" HANDLE WINAPI GetCurrentProcess(void); """
GetCurrentProcess = WINAPI(HANDLE)(('GetCurrentProcess', _kernel32))
hCurrentProcess = GetCurrentProcess()
""" LPVOID WINAPI VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) """
VirtualAlloc = WINAPI(LPVOID, LPVOID, SIZE_T, DWORD, DWORD)(
_kernel32.VirtualAlloc
)
""" BOOL VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) """
VirtualFree = WINAPI(BOOL, LPVOID, SIZE_T, DWORD)(
_kernel32.VirtualFree
)
""" BOOL VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) """
VirtualProtect = WINAPI(BOOL, LPVOID, SIZE_T, DWORD, PDWORD)(
_kernel32.VirtualProtect
)
""" BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumofBytesWritten) """
WriteProcessMemory = WINAPI(BOOL, HANDLE, LPVOID, LPCVOID, SIZE_T, PSIZE_T)(
_kernel32.WriteProcessMemory
)
""" BOOL WINAPI FlushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize) """
FlushInstructionCache = WINAPI(BOOL, HANDLE, LPCVOID, SIZE_T)(
_kernel32.FlushInstructionCache
)
def destroy_cfunc(cfuncproc):
"""
:param cfuncproc:Stuff
:type cfuncproc:ctypes.CFUNCTYPE
:return:Success
:rtype:bool
"""
if isinstance(cfuncproc, LPVOID):
cptr = cfuncproc
csize = cfuncproc._allocsize
else:
cptr = cfuncproc._cptr
csize = cfuncproc._procsize
return bool(VirtualFree(cptr, csize, MEM_RELEASE))
def create_cfunc(cfunctype, shellcode):
"""
:param cfunctype: The function prototype to use for creation.
:type cfunctype: ctypes.CFUNCTYPE
:param shellcode: List of bytes forming the shellcode
:type shellcode: list
:return:The callable function in memory.
:rtype:ctypes.CFUNCTYPE
"""
# Grab the size of the shellcode
shellcode_size = len(shellcode)
# Reserve memory for our shellcode bytes
lpAllocated = LPVOID(VirtualAlloc(NULL, shellcode_size, MEM_RESERVE, PAGE_EXECUTE_READWRITE))
if not lpAllocated or (hasattr(lpAllocated, 'value') and lpAllocated.value is None):
raise WinError()
# Commit our allocation to obtain our allocated memory.
lpRes = VirtualAlloc(lpAllocated.value, shellcode_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
lpAllocated._allocsize = shellcode_size
# Alter protection flags on the memory region that will contain our code.
# if not VirtualProtect(lpAllocated.value, shellcode_size, PAGE_EXECUTE_READWRITE, NULL_PDWORD):
# destroy_cfunc(lpAllocated)
# raise WinError()
# Assemble our shellcode buffer, then copy it over to our allocated memory.
shellcode_buffer = STRALLOC(''.join(map(chr, shellcode)), shellcode_size)
WriteProcessMemory(hCurrentProcess, lpAllocated, CAST(shellcode_buffer, LPVOID).value, shellcode_size, NULL_PSIZE_T)
# Flush our instruction cache, and apply our prototype, then return the result.
FlushInstructionCache(hCurrentProcess, lpAllocated, shellcode_size)
cfuncproc = cfunctype(lpAllocated.value)
cfuncproc._cptr = lpAllocated
cfuncproc._procsize = shellcode_size
return cfuncproc
IsWow64ShellCode = [ # _IsWow64:
0x66, 0x8C, 0xC8, # mov ax, cs
0xC1, 0xE8, 0x05, # shr eax, 5
0xC3 # ret
]
ISWOW64FUNCTYPE = CDECL(BOOLEAN)
IsWow64 = create_cfunc(ISWOW64FUNCTYPE, IsWow64ShellCode)
if IsWow64():
print 'IsWow64 = True'
else:
print 'IsWow64 = False'
destroy_cfunc(IsWow64)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment