#coding: utf-8
import ida_dbg
import idc
import idaapi
import funcutils

GENERIC_ALL = 0x10000000
GENERIC_EXECUTE = 0x20000000
GENERIC_WRITE = 0x40000000
GENERIC_READ = 0x80000000

FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004

CREATE_NEW = 1
CREATE_ALWAYS = 2
OPEN_EXISTING = 3
OPEN_ALWAYS = 4
TRUNCATE_EXISTING = 5

FILE_ATTRIBUTE_READONLY = 0x00000001
FILE_ATTRIBUTE_HIDDEN = 0x00000002
FILE_ATTRIBUTE_SYSTEM = 0x00000004
FILE_ATTRIBUTE_ARCHIVE = 0x0000020
FILE_ATTRIBUTE_NORMAL = 0x00000080
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
FILE_ATTRIBUTE_OFFLINE = 0x00001000
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000

class Kernel32:
    def __init__(self):
        self.is_64bit = True if idaapi.BADADDR == 0xffffffffffffffff else False
        self.total_func = {
            # file
            "CreateFileA" : self.CreateFileA,
            "CreateFileW" : self.CreateFileW,
            "ReadFile" : self.ReadFile,
            "WriteFile" : self.WriteFile,
            # thread & process
            "CreateThread" : self.CreateThread,
            "CreateProcessA": self.CreateProcessA,
            "CreateProcessW": self.CreateProcessW,
            # memory
            "VirtualAlloc":self.VirtualAlloc,
            "VirtualFree":self.VirtualFree,
            "VirtualProtect":self.VirtualProtect,
            # debug
            "IsDebuggerPresent":self.IsDebuggerPresent
        }
    def get_result(self):
        if self.is_64bit:
            res = idc.get_reg_value("RAX")
        else:
            res = idc.get_reg_value("EAX")
        return res
    def get_func_args(self, nth):
        ida_dbg.refresh_debugger_memory()
        if self.is_64bit:
            four_args = ["RCX", "RDX", "R8", "R9"]
            if nth == 0:
                rsp = idc.get_reg_value("RSP")
                result = idc.get_qword(rsp)
            elif nth < 5:
                result = idc.get_reg_value(four_args[nth - 1])
            else:
                rsp = idc.get_reg_value("RSP")
                result = idc.get_qword(rsp + nth * 8)
        else:
            esp = idc.get_reg_value("ESP")
            result = idc.get_wide_dword(esp + nth * 4)
        return result
    def CreateFileA(self, is_return = False):
        if is_return == True:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> HANDLE"
        
        lpFileNameAddr = funcutils.get_func_args(1, self.is_64bit)
        _debug_info = f"lpFileName=" + idc.get_strlit_contents(lpFileNameAddr).decode('utf-8')
        
        access = funcutils.get_func_args(2, self.is_64bit) & 0xffffffff
        access_result = str()
        if access == GENERIC_ALL:
            access_result = "GENERIC_ALL"
        else:
            if access & GENERIC_READ:
                access_result += "GENERIC_READ|"
            if access & GENERIC_WRITE:
                access_result += "GENERIC_WRITE|"
            if access & GENERIC_EXECUTE:
                access_result += "GENERIC_EXECUTE|"
        if access_result.endswith('|'):
            access_result = access_result[:-1]
        _debug_info += f", dwDesiredAccess={access_result}"
        
        shared_mode = funcutils.get_func_args(3, self.is_64bit) & 0xffffffff
        shared_mode_result = str()
        if shared_mode == 0:
            shared_mode_result = "0"
        else:
            if shared_mode & FILE_SHARE_READ:
                shared_mode_result += "FILE_SHARE_READ|"
            if shared_mode & FILE_SHARE_WRITE:
                shared_mode_result += "FILE_SHARE_WRITE|"
            if shared_mode & FILE_SHARE_DELETE:
                shared_mode_result += "FILE_SHARE_DELETE|"
        if shared_mode_result.endswith("|"):
            shared_mode_result = shared_mode_result[:-1]
        _debug_info += f", dwShareMode={shared_mode_result}"

        lpSecurityAttributes = funcutils.get_func_args(4, self.is_64bit)
        _debug_info += f", lpSecurityAttributes={hex(lpSecurityAttributes)}"

        dwCreationDisposition = funcutils.get_func_args(5, self.is_64bit) & 0xffffffff
        creation_result = str()
        if dwCreationDisposition == CREATE_NEW:
            creation_result = "CREATE_NEW"
        elif dwCreationDisposition == CREATE_ALWAYS:
            creation_result = "CREATE_ALWAYS"
        elif dwCreationDisposition == OPEN_EXISTING:
            creation_result = "OPEN_EXISTING"
        elif dwCreationDisposition == OPEN_ALWAYS:
            creation_result = "OPEN_ALWAYS"
        elif dwCreationDisposition == TRUNCATE_EXISTING:
            creation_result = "TRUNCATE_EXISTING"
        _debug_info += f", dwCreationDisposition={creation_result}"

        dwFlagsAndAttributes = funcutils.get_func_args(6, self.is_64bit) & 0xffffffff
        attr_result = str()
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY:
            attr_result += "FILE_ATTRIBUTE_READONLY|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN:
            attr_result += "FILE_ATTRIBUTE_HIDDEN|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM:
            attr_result += "FILE_ATTRIBUTE_SYSTEM|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE:
            attr_result += "FILE_ATTRIBUTE_ARCHIVE|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL:
            attr_result += "FILE_ATTRIBUTE_NORMAL|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY:
            attr_result += "FILE_ATTRIBUTE_TEMPORARY|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE:
            attr_result += "FILE_ATTRIBUTE_OFFLINE|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED:
            attr_result += "FILE_ATTRIBUTE_ENCRYPTED|"
        
        if attr_result.endswith('|'):
            attr_result = attr_result[:-1]
        _debug_info += f", dwFlagsAndAttributes={attr_result}"

        hTemplateFile = funcutils.get_func_args(7, self.is_64bit)
        _debug_info += f", hTemplateFile={hex(hTemplateFile)}) = "

        return _debug_info
    def CreateFileW(self, is_return = False):
        if is_return == True:
            return f"{hex(funcutils.get_result(self.is_64bit))} => HANDLE"
        
        lpFileNameAddr = funcutils.get_func_args(1, self.is_64bit)
        _debug_info = f"lpFileName=" + idc.get_strlit_contents(ea = lpFileNameAddr, strtype=idc.STRTYPE_C16).decode("utf-8")
        
        access = funcutils.get_func_args(2, self.is_64bit) & 0xffffffff
        access_result = str()
        if access == GENERIC_ALL:
            access_result = "GENERIC_ALL"
        else:
            if access & GENERIC_READ:
                access_result += "GENERIC_READ|"
            if access & GENERIC_WRITE:
                access_result += "GENERIC_WRITE|"
            if access & GENERIC_EXECUTE:
                access_result += "GENERIC_EXECUTE|"
        if access_result.endswith('|'):
            access_result = access_result[:-1]
        _debug_info += f", dwDesiredAccess={access_result}"
        
        shared_mode = funcutils.get_func_args(3, self.is_64bit) & 0xffffffff
        shared_mode_result = str()
        if shared_mode == 0:
            shared_mode_result = "0"
        else:
            if shared_mode & FILE_SHARE_READ:
                shared_mode_result += "FILE_SHARE_READ|"
            if shared_mode & FILE_SHARE_WRITE:
                shared_mode_result += "FILE_SHARE_WRITE|"
            if shared_mode & FILE_SHARE_DELETE:
                shared_mode_result += "FILE_SHARE_DELETE|"
        if shared_mode_result.endswith("|"):
            shared_mode_result = shared_mode_result[:-1]
        _debug_info += f", dwShareMode={shared_mode_result}"

        lpSecurityAttributes = funcutils.get_func_args(4, self.is_64bit)
        _debug_info += f", lpSecurityAttributes={hex(lpSecurityAttributes)}"

        dwCreationDisposition = funcutils.get_func_args(5, self.is_64bit) & 0xffffffff
        creation_result = str()
        if dwCreationDisposition == CREATE_NEW:
            creation_result = "CREATE_NEW"
        elif dwCreationDisposition == CREATE_ALWAYS:
            creation_result = "CREATE_ALWAYS"
        elif dwCreationDisposition == OPEN_EXISTING:
            creation_result = "OPEN_EXISTING"
        elif dwCreationDisposition == OPEN_ALWAYS:
            creation_result = "OPEN_ALWAYS"
        elif dwCreationDisposition == TRUNCATE_EXISTING:
            creation_result = "TRUNCATE_EXISTING"
        _debug_info += f", dwCreationDisposition={creation_result}"

        dwFlagsAndAttributes = funcutils.get_func_args(6, self.is_64bit) & 0xffffffff
        attr_result = str()
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_READONLY:
            attr_result += "FILE_ATTRIBUTE_READONLY|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_HIDDEN:
            attr_result += "FILE_ATTRIBUTE_HIDDEN|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_SYSTEM:
            attr_result += "FILE_ATTRIBUTE_SYSTEM|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_ARCHIVE:
            attr_result += "FILE_ATTRIBUTE_ARCHIVE|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_NORMAL:
            attr_result += "FILE_ATTRIBUTE_NORMAL|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_TEMPORARY:
            attr_result += "FILE_ATTRIBUTE_TEMPORARY|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_OFFLINE:
            attr_result += "FILE_ATTRIBUTE_OFFLINE|"
        if dwFlagsAndAttributes & FILE_ATTRIBUTE_ENCRYPTED:
            attr_result += "FILE_ATTRIBUTE_ENCRYPTED|"
        
        if attr_result.endswith('|'):
            attr_result = attr_result[:-1]
        _debug_info += f", dwFlagsAndAttributes={attr_result}"

        hTemplateFile = funcutils.get_func_args(7, self.is_64bit)
        _debug_info += f", hTemplateFile={hex(hTemplateFile)}) = "

        return _debug_info
    def ReadFile(self, is_return = False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> BOOL"

        hFile = funcutils.get_func_args(1, self.is_64bit)
        lpBuffer = funcutils.get_func_args(2, self.is_64bit)
        nNumberOfBytesToRead = funcutils.get_func_args(3, self.is_64bit)
        lpNumberOfBytesRead = funcutils.get_func_args(4, self.is_64bit)
        lpOverlapped = funcutils.get_func_args(5, self.is_64bit)

        _debug_info = f"hFile={hex(hFile)}, "
        _debug_info += f"lpBuffer={hex(lpBuffer)}, "
        _debug_info += f"nNumberOfBytesToRead={nNumberOfBytesToRead}, "
        _debug_info += f"lpNumberOfBytesRead={hex(lpNumberOfBytesRead)}, "
        _debug_info += f"lpOverlapped={hex(lpOverlapped)}) = "
        return _debug_info
    def WriteFile(self, is_return = False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> BOOL"

        hFile = funcutils.get_func_args(1, self.is_64bit)
        lpBuffer = funcutils.get_func_args(2, self.is_64bit)
        nNumberOfBytesToWrite = funcutils.get_func_args(3, self.is_64bit)
        lpNumberOfBytesWritten = funcutils.get_func_args(4, self.is_64bit)
        lpOverlapped = funcutils.get_func_args(5, self.is_64bit)

        buffer_preview = ""
        if lpBuffer != 0:
            buffer_bytes = idc.get_bytes(lpBuffer, min(5, nNumberOfBytesToWrite))
            if buffer_bytes:
                buffer_preview = " ".join(f"{b:02X}" for b in buffer_bytes)
                if nNumberOfBytesToWrite > 5:
                    buffer_preview += " ..."
        _debug_info = f"hFile={hex(hFile)}, "
        _debug_info += f"lpBuffer={hex(lpBuffer)}, Buffer Preview: [{buffer_preview}], "
        _debug_info += f"nNumberOfBytesToWrite={nNumberOfBytesToWrite}, "
        _debug_info += f"lpNumberOfBytesWritten={hex(lpNumberOfBytesWritten)}, "
        _debug_info += f"lpOverlapped={hex(lpOverlapped)}) = "
        return _debug_info
    def CloseHandle(self, is_return=False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> BOOL"

        hObject = self.get_func_args(1)
        _debug_info = f"hObject={hex(hObject)}) = "
        return _debug_info
    def CreateThread(self, is_return = False):
        if is_return:
            lpThreadId = funcutils.get_func_args(5, self.is_64bit)
            if lpThreadId != 0:
                thread_id = idc.get_wide_dword(lpThreadId)
                return f"{hex(funcutils.get_result(self.is_64bit))} -> HANDLE, tid = {hex(thread_id)}"
            return f"{hex(funcutils.get_result(self.is_64bit))} -> HANDLE"

        lpThreadAttributes = funcutils.get_func_args(1, self.is_64bit)
        dwStackSize = funcutils.get_func_args(2, self.is_64bit)
        lpStartAddress = funcutils.get_func_args(3, self.is_64bit)
        lpParameter = funcutils.get_func_args(4, self.is_64bit)
        dwCreationFlags = funcutils.get_func_args(5, self.is_64bit)
        lpThreadId = funcutils.get_func_args(6, self.is_64bit)

        creation_flags_descr = []
        if dwCreationFlags & 0x00000004:  # CREATE_SUSPENDED
            creation_flags_descr.append("CREATE_SUSPENDED")
        if dwCreationFlags & 0x00010000:  # STACK_SIZE_PARAM_IS_A_RESERVATION
            creation_flags_descr.append("STACK_SIZE_PARAM_IS_A_RESERVATION")

        if creation_flags_descr:
            creation_flags_descr = '|'.join(creation_flags_descr)
        else:
            creation_flags_descr = '0'

        _debug_info = f"lpThreadAttributes={hex(lpThreadAttributes)}, "
        _debug_info += f"dwStackSize={dwStackSize}, "
        _debug_info += f"lpStartAddress={hex(lpStartAddress)}, "
        _debug_info += f"lpParameter={hex(lpParameter)}, "
        _debug_info += f"dwCreationFlags={creation_flags_descr}, "
        _debug_info += f"lpThreadId={hex(lpThreadId)}) = "
        return _debug_info
    def CreateRemoteThread(self, is_return=False):
        if is_return:
            lpThreadIdAddr = funcutils.get_func_args(6, self.is_64bit)
            if lpThreadIdAddr != 0:
                thread_id = idc.get_wide_dword(lpThreadIdAddr)
                return f"{hex(funcutils.get_result(self.is_64bit))} -> HANDLE, tid = {hex(thread_id)}"
            return f"{hex(funcutils.get_result(self.is_64bit))} -> HANDLE"

        # 获取参数
        hProcess = funcutils.get_func_args(1, self.is_64bit)
        lpThreadAttributes = funcutils.get_func_args(2, self.is_64bit)
        dwStackSize = funcutils.get_func_args(3, self.is_64bit)
        lpStartAddress = funcutils.get_func_args(4, self.is_64bit)
        lpParameter = funcutils.get_func_args(5, self.is_64bit)
        dwCreationFlags = funcutils.get_func_args(6, self.is_64bit)
        lpThreadId = funcutils.get_func_args(7, self.is_64bit)

        # 解析 dwCreationFlags 标志
        creation_flags_descr = []
        if dwCreationFlags & 0x00000004:  # CREATE_SUSPENDED
            creation_flags_descr.append("CREATE_SUSPENDED")
        if dwCreationFlags & 0x00010000:  # STACK_SIZE_PARAM_IS_A_RESERVATION
            creation_flags_descr.append("STACK_SIZE_PARAM_IS_A_RESERVATION")

        creation_flags_str = '|'.join(creation_flags_descr) if creation_flags_descr else '0'

        _debug_info = (f"hProcess={hex(hProcess)}, "
                    f"lpThreadAttributes={hex(lpThreadAttributes)}, "
                    f"dwStackSize={dwStackSize}, "
                    f"lpStartAddress={hex(lpStartAddress)}, "
                    f"lpParameter={hex(lpParameter)}, "
                    f"dwCreationFlags={creation_flags_str}, "
                    f"lpThreadId={hex(lpThreadId)}) = ")

        return _debug_info
    def CreateProcessA(self, is_return=False):
        def parse_creation_flags(dwCreationFlags):
            flags = []
            if dwCreationFlags & 0x04000000:
                flags.append("CREATE_DEFAULT_ERROR_MODE")
            if dwCreationFlags & 0x00000010:
                flags.append("CREATE_NEW_CONSOLE")
            if dwCreationFlags & 0x00000200:
                flags.append("CREATE_NEW_PROCESS_GROUP")
            if dwCreationFlags & 0x08000000:
                flags.append("CREATE_NO_WINDOW")
            if dwCreationFlags & 0x00000004:
                flags.append("CREATE_SUSPENDED")
            if dwCreationFlags & 0x00000002:
                flags.append("DEBUG_ONLY_THIS_PROCESS")
            if dwCreationFlags & 0x00000001:
                flags.append("DEBUG_PROCESS")
            if dwCreationFlags & 0x00000008:
                flags.append("DETACHED_PROCESS")
            if dwCreationFlags & 0x00010000:
                flags.append("INHERIT_PARENT_AFFINITY")
            return '|'.join(flags) if flags else '0'
        
        if is_return:
            return_value = funcutils.get_result(self.is_64bit)
            success = "Success" if return_value else "Failure"
            return f"{success} -> BOOL"

        lpApplicationName = funcutils.get_func_args(1, self.is_64bit)
        lpCommandLine = funcutils.get_func_args(2, self.is_64bit)
        lpProcessAttributes = funcutils.get_func_args(3, self.is_64bit)
        lpThreadAttributes = funcutils.get_func_args(4, self.is_64bit)
        bInheritHandles = funcutils.get_func_args(5, self.is_64bit)
        dwCreationFlags = funcutils.get_func_args(6, self.is_64bit)
        lpEnvironment = funcutils.get_func_args(7, self.is_64bit)
        lpCurrentDirectory = funcutils.get_func_args(8, self.is_64bit)
        lpStartupInfo = funcutils.get_func_args(9, self.is_64bit)
        lpProcessInformation = funcutils.get_func_args(10, self.is_64bit)

        app_name = idc.get_strlit_contents(lpApplicationName).decode('utf-8') if lpApplicationName else "null"
        cmd_line = idc.get_strlit_contents(lpCommandLine).decode('utf-8') if lpCommandLine else "null"
        process_attr = f"{hex(lpProcessAttributes)}"
        thread_attr = f"{hex(lpThreadAttributes)}"
        inherit_handles = "TRUE" if bInheritHandles else "FALSE"
        creation_flags = parse_creation_flags(dwCreationFlags)
        environment = f"{hex(lpEnvironment)}"
        current_dir = idc.get_strlit_contents(lpCurrentDirectory).decode('utf-8') if lpCurrentDirectory else "null"
        startup_info = f"{hex(lpStartupInfo)}"
        process_info = f"{hex(lpProcessInformation)}"

        _debug_info = (f"lpApplicationName={app_name}, "
                   f"lpCommandLine={cmd_line}, "
                   f"lpProcessAttributes={process_attr}, "
                   f"lpThreadAttributes={thread_attr}, "
                   f"bInheritHandles={inherit_handles}, "
                   f"dwCreationFlags={creation_flags}, "
                   f"lpEnvironment={environment}, "
                   f"lpCurrentDirectory={current_dir}, "
                   f"lpStartupInfo={startup_info}, "
                   f"lpProcessInformation={process_info}) = ")
        
        return _debug_info
    def CreateProcessW(self, is_return=False):
        def parse_creation_flags(dwCreationFlags):
            flags = []
            if dwCreationFlags & 0x04000000:
                flags.append("CREATE_DEFAULT_ERROR_MODE")
            if dwCreationFlags & 0x00000010:
                flags.append("CREATE_NEW_CONSOLE")
            if dwCreationFlags & 0x00000200:
                flags.append("CREATE_NEW_PROCESS_GROUP")
            if dwCreationFlags & 0x08000000:
                flags.append("CREATE_NO_WINDOW")
            if dwCreationFlags & 0x00000004:
                flags.append("CREATE_SUSPENDED")
            if dwCreationFlags & 0x00000002:
                flags.append("DEBUG_ONLY_THIS_PROCESS")
            if dwCreationFlags & 0x00000001:
                flags.append("DEBUG_PROCESS")
            if dwCreationFlags & 0x00000008:
                flags.append("DETACHED_PROCESS")
            if dwCreationFlags & 0x00010000:
                flags.append("INHERIT_PARENT_AFFINITY")
            return '|'.join(flags) if flags else '0'
        
        if is_return:
            return_value = funcutils.get_result(self.is_64bit)
            success = "Success" if return_value else "Failure"
            return f"{success} -> BOOL"

        lpApplicationName = funcutils.get_func_args(1, self.is_64bit)
        lpCommandLine = funcutils.get_func_args(2, self.is_64bit)
        lpProcessAttributes = funcutils.get_func_args(3, self.is_64bit)
        lpThreadAttributes = funcutils.get_func_args(4, self.is_64bit)
        bInheritHandles = funcutils.get_func_args(5, self.is_64bit)
        dwCreationFlags = funcutils.get_func_args(6, self.is_64bit)
        lpEnvironment = funcutils.get_func_args(7, self.is_64bit)
        lpCurrentDirectory = funcutils.get_func_args(8, self.is_64bit)
        lpStartupInfo = funcutils.get_func_args(9, self.is_64bit)
        lpProcessInformation = funcutils.get_func_args(10, self.is_64bit)

        app_name = idc.get_strlit_contents(ea = lpApplicationName, strtype=idc.STRTYPE_C16).decode('utf-8') if lpApplicationName else "null"
        cmd_line = idc.get_strlit_contents(ea = lpCommandLine, strtype=idc.STRTYPE_C16).decode('utf-8') if lpCommandLine else "null"
        process_attr = f"{hex(lpProcessAttributes)}"
        thread_attr = f"{hex(lpThreadAttributes)}"
        inherit_handles = "TRUE" if bInheritHandles else "FALSE"
        creation_flags = parse_creation_flags(dwCreationFlags)
        environment = f"{hex(lpEnvironment)}"
        current_dir = idc.get_strlit_contents(ea=lpCurrentDirectory, strtype=idc.STRTYPE_C16).decode('utf-8') if lpCurrentDirectory else "null"
        startup_info = f"{hex(lpStartupInfo)}"
        process_info = f"{hex(lpProcessInformation)}"

        _debug_info = (f"lpApplicationName={app_name}, "
                   f"lpCommandLine={cmd_line}, "
                   f"lpProcessAttributes={process_attr}, "
                   f"lpThreadAttributes={thread_attr}, "
                   f"bInheritHandles={inherit_handles}, "
                   f"dwCreationFlags={creation_flags}, "
                   f"lpEnvironment={environment}, "
                   f"lpCurrentDirectory={current_dir}, "
                   f"lpStartupInfo={startup_info}, "
                   f"lpProcessInformation={process_info}) = ")
        
        return _debug_info    # anti debug
    def IsDebuggerPresent(self, is_return = False):
        if is_return:
            idc.set_reg_value(0, "EAX")
            return f"0 -> BOOL"

        _debug_info = ")="
        return _debug_info
    def GetProcAddress(self, is_return = False):
        if is_return == True:
            return f" = {hex(funcutils.get_result(self.is_64bit))} -> FARPROC"
        hModule = funcutils.get_func_args(1, self.is_64bit)
        _debug_info = "kernel32!GetProcAddress("
        _debug_info += f"hModule={hex(hModule)}, "
        lpProcNameAddr = funcutils.get_func_args(2, self.is_64bit)
        func_name += idc.get_strlit_contents(lpProcNameAddr).decode("utf-8")
        _debug_info += f"lpProcName={func_name})"
        return _debug_info
    # memory
    def VirtualAlloc(self, is_return=False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> LPVOID"

        lpAddress = funcutils.get_func_args(1, self.is_64bit)
        dwSize = funcutils.get_func_args(2, self.is_64bit)
        flAllocationType = funcutils.get_func_args(3, self.is_64bit)
        flProtect = funcutils.get_func_args(4, self.is_64bit)

        allocation_flags = []
        if flAllocationType & 0x00001000:
            allocation_flags.append("MEM_COMMIT")
        if flAllocationType & 0x00002000:
            allocation_flags.append("MEM_RESERVE")
        if flAllocationType & 0x00008000:
            allocation_flags.append("MEM_RESET")
        allocation_flags_str = '|'.join(allocation_flags) if allocation_flags else '0'

        protection_flags = []
        if flProtect & 0x01:
            protection_flags.append("PAGE_NOACCESS")
        if flProtect & 0x02:
            protection_flags.append("PAGE_READONLY")
        if flProtect & 0x04:
            protection_flags.append("PAGE_READWRITE")
        if flProtect & 0x08:
            protection_flags.append("PAGE_WRITECOPY")
        protection_flags_str = '|'.join(protection_flags) if protection_flags else '0'

        _debug_info = (f"lpAddress={hex(lpAddress)}, "
                    f"dwSize={dwSize}, "
                    f"flAllocationType={allocation_flags_str}, "
                    f"flProtect={protection_flags_str}) = ")

        return _debug_info
    def VirtualFree(self, is_return=False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> BOOL"

        lpAddress = funcutils.get_func_args(1, self.is_64bit)
        dwSize = funcutils.get_func_args(2, self.is_64bit)
        dwFreeType = funcutils.get_func_args(3, self.is_64bit)

        free_flags = []
        if dwFreeType & 0x00008000:
            free_flags.append("MEM_DECOMMIT")
        if dwFreeType & 0x00004000:
            free_flags.append("MEM_RELEASE")
        free_flags_str = '|'.join(free_flags) if free_flags else '0'

        _debug_info = (f"lpAddress={hex(lpAddress)}, "
                    f"dwSize={dwSize}, "
                    f"dwFreeType={free_flags_str}) = ")

        return _debug_info
    def VirtualProtect(self, is_return=False):
        if is_return:
            return f"{hex(funcutils.get_result(self.is_64bit))} -> BOOL"

        lpAddress = funcutils.get_func_args(1, self.is_64bit)
        dwSize = funcutils.get_func_args(2, self.is_64bit)
        flNewProtect = funcutils.get_func_args(3, self.is_64bit)
        lpflOldProtect = funcutils.get_func_args(4, self.is_64bit)

        protection_flags = []
        if flNewProtect & 0x01:
            protection_flags.append("PAGE_NOACCESS")
        if flNewProtect & 0x02:
            protection_flags.append("PAGE_READONLY")
        if flNewProtect & 0x04:
            protection_flags.append("PAGE_READWRITE")
        if flNewProtect & 0x08:
            protection_flags.append("PAGE_WRITECOPY")
        if flNewProtect & 0x10:
            protection_flags.append("PAGE_EXECUTE")
        if flNewProtect & 0x20:
            protection_flags.append("PAGE_EXECUTE_READ")
        if flNewProtect & 0x40:
            protection_flags.append("PAGE_EXECUTE_READWRITE")
        if flNewProtect & 0x80:
            protection_flags.append("PAGE_EXECUTE_WRITECOPY")
        if flNewProtect & 0x100:
            protection_flags.append("PAGE_GUARD")
        if flNewProtect & 0x200:
            protection_flags.append("PAGE_NOCACHE")
        if flNewProtect & 0x400:
            protection_flags.append("PAGE_WRITECOMBINE")

        protection_flags_str = '|'.join(protection_flags) if protection_flags else 'UNKNOWN'

        _debug_info = (f"lpAddress={hex(lpAddress)}, "
                    f"dwSize={dwSize}, "
                    f"flNewProtect={protection_flags_str}, "
                    f"lpflOldProtect={hex(lpflOldProtect)}) = ")

        return _debug_info