如何让披了外壳的样例露出真身,让IDA对其真身分析
脱壳准备工作,IDA静态分析半自动完成以下函数集静态变量重命名,
其中得到导入表位置,通过IDAPython自动生成OD Script修复IAT,
最后通过IMportRec重新建立导入表
00444108 Hi_crtmain
004442A2 Hi_start
00444509 Hi_Init_UnhandledExceptionFilter
00444515 Hi_UnhandledExceptionFilter
004447BD Hi_security_cookie_init
00489008 Hi_security_cook_not
0048900C Hi_security_cook
004A9B88 Hi_init0
004AD000 Hi_fp_ADVAPI32_RegOpenKeyExW_4AD000
004AD004 Hi_fp_ADVAPI32_RegDeleteValueW_4AD004
004AD008 Hi_fp_ADVAPI32_RegCreateKeyExW_4AD008
004AD00C Hi_fp_ADVAPI32_RegSetValueExW_4AD00C
004AD010 Hi_fp_ADVAPI32_RegDeleteKeyW_4AD010
004AD014 Hi_fp_ADVAPI32_RegEnumKeyExW_4AD014
004AD018 Hi_fp_ADVAPI32_RegQueryInfoKeyW_4AD018
004AD01C Hi_fp_ADVAPI32_RegCloseKey_4AD01C
004AD024 Hi_fp_COMCTL32_InitCommonControlsEx_4AD024
004AD02C Hi_fp_KERNEL32_VirtualAlloc_4AD02C
004AD030 Hi_fp_KERNEL32_ExitProcess_4AD030
004AD034 Hi_fp_KERNEL32_FreeLibrary_4AD034
004AD038 Hi_fp_KERNEL32_GetProcAddress_4AD038
004AD03C Hi_fp_KERNEL32_lstrcmpiW_4AD03C
004AD040 Hi_fp_KERNEL32_LeaveCriticalSection_4AD040
004AD044 Hi_fp_KERNEL32_RaiseException_4AD044
004AD048 Hi_fp_KERNEL32_EnterCriticalSection_4AD048
004AD04C Hi_fp_KERNEL32_GetLastError_4AD04C
004AD050 Hi_fp_KERNEL32_MultiByteToWideChar_4AD050
004AD054 Hi_fp_KERNEL32_SizeofResource_4AD054
004AD058 Hi_fp_KERNEL32_LoadResource_4AD058
004AD05C Hi_fp_KERNEL32_FindResourceW_4AD05C
004AD060 Hi_fp_KERNEL32_LoadLibraryExW_4AD060
004AD064 Hi_fp_KERNEL32_GetModuleFileNameW_4AD064
004AD068 Hi_fp_KERNEL32_InitializeCriticalSectionAndSpinCount_4AD068
004AD06C Hi_fp_KERNEL32_DeleteCriticalSection_4AD06C
004AD070 Hi_fp_KERNEL32_InterlockedDecrement_4AD070
004AD074 Hi_fp_KERNEL32_InterlockedIncrement_4AD074
004AD078 Hi_fp_KERNEL32_GetCurrentThreadId_4AD078
004AD07C Hi_fp_KERNEL32_DecodePointer_4AD07C
004AD080 Hi_fp_KERNEL32_SetLastError_4AD080
004AD084 Hi_fp_KERNEL32_InitializeCriticalSection_4AD084
004AD088 Hi_fp_KERNEL32_GetCurrentThread_4AD088
004AD08C Hi_fp_KERNEL32_GetThreadContext_4AD08C
004AD090 Hi_fp_KERNEL32_CreateFileW_4AD090
004AD094 Hi_fp_KERNEL32_WideCharToMultiByte_4AD094
004AD098 Hi_fp_KERNEL32_GetUserDefaultLangID_4AD098
004AD09C Hi_fp_KERNEL32_lstrcatA_4AD09C
004AD0A0 Hi_fp_KERNEL32_lstrlenA_4AD0A0
004AD0A4 Hi_fp_KERNEL32_WaitForSingleObject_4AD0A4
004AD0A8 Hi_fp_KERNEL32_CloseHandle_4AD0A8
004AD0AC Hi_fp_KERNEL32_CreateThread_4AD0AC
004AD0B0 Hi_fp_KERNEL32_SetThreadPriority_4AD0B0
004AD0B4 Hi_fp_KERNEL32_HeapAlloc_4AD0B4
004AD0B8 Hi_fp_KERNEL32_HeapCreate_4AD0B8
004AD0BC Hi_fp_KERNEL32_HeapDestroy_4AD0BC
004AD0C0 Hi_fp_KERNEL32_Sleep_4AD0C0
004AD0C4 Hi_fp_KERNEL32_CreateFileA_4AD0C4
004AD0C8 Hi_fp_KERNEL32_ReadFile_4AD0C8
004AD0CC Hi_fp_KERNEL32_SetFilePointer_4AD0CC
004AD0D0 Hi_fp_KERNEL32_FindResourceA_4AD0D0
004AD0D4 Hi_fp_KERNEL32_GetOEMCP_4AD0D4
004AD0D8 Hi_fp_KERNEL32_IsValidCodePage_4AD0D8
004AD0DC Hi_fp_KERNEL32_GetCurrentProcess_4AD0DC
004AD0E0 Hi_fp_KERNEL32_FindNextFileA_4AD0E0
004AD0E4 Hi_fp_KERNEL32_FindFirstFileExW_4AD0E4
004AD0E8 Hi_fp_KERNEL32_FindFirstFileExA_4AD0E8
004AD0EC Hi_fp_KERNEL32_FindClose_4AD0EC
004AD0F0 Hi_fp_KERNEL32_EnumSystemLocalesW_4AD0F0
004AD0F4 Hi_fp_KERNEL32_GetUserDefaultLCID_4AD0F4
004AD0F8 Hi_fp_KERNEL32_IsValidLocale_4AD0F8
004AD0FC Hi_fp_KERNEL32_GetLocaleInfoW_4AD0FC
004AD100 Hi_fp_KERNEL32_LCMapStringW_4AD100
004AD104 Hi_fp_KERNEL32_CompareStringW_4AD104
004AD108 Hi_fp_KERNEL32_GetTimeFormatW_4AD108
004AD10C Hi_fp_KERNEL32_GetDateFormatW_4AD10C
004AD110 Hi_fp_KERNEL32_ReadConsoleW_4AD110
004AD114 Hi_fp_KERNEL32_GetConsoleMode_4AD114
004AD118 Hi_fp_KERNEL32_SetConsoleCtrlHandler_4AD118
004AD11C Hi_fp_KERNEL32_HeapReAlloc_4AD11C
004AD120 Hi_fp_KERNEL32_HeapSize_4AD120
004AD124 Hi_fp_KERNEL32_GetACP_4AD124
004AD128 Hi_fp_KERNEL32_WriteFile_4AD128
004AD12C Hi_fp_KERNEL32_GetStdHandle_4AD12C
004AD130 Hi_fp_KERNEL32_GetModuleFileNameA_4AD130
004AD134 Hi_fp_KERNEL32_GetModuleHandleExW_4AD134
004AD138 Hi_fp_KERNEL32_RtlUnwind_4AD138
004AD13C Hi_fp_KERNEL32_TlsFree_4AD13C
004AD140 Hi_fp_KERNEL32_TlsSetValue_4AD140
004AD144 Hi_fp_KERNEL32_TlsGetValue_4AD144
004AD148 Hi_fp_KERNEL32_TlsAlloc_4AD148
004AD14C Hi_fp_KERNEL32_InterlockedFlushSList_4AD14C
004AD150 Hi_fp_KERNEL32_GetCPInfo_4AD150
004AD154 Hi_fp_KERNEL32_TerminateProcess_4AD154
004AD158 Hi_fp_KERNEL32_GetSystemTimeAsFileTime_4AD158
004AD15C Hi_fp_KERNEL32_GetCurrentProcessId_4AD15C
004AD160 Hi_fp_KERNEL32_QueryPerformanceCounter_4AD160
004AD164 Hi_fp_KERNEL32_GetStartupInfoW_4AD164
004AD168 Hi_fp_KERNEL32_SetUnhandledExceptionFilter_4AD168
004AD16C Hi_fp_KERNEL32_UnhandledExceptionFilter_4AD16C
004AD170 Hi_fp_KERNEL32_GetModuleHandleW_4AD170
004AD174 Hi_fp_KERNEL32_VirtualFree_4AD174
004AD178 Hi_fp_KERNEL32_OutputDebugStringA_4AD178
004AD17C Hi_fp_KERNEL32_SetStdHandle_4AD17C
004AD180 Hi_fp_KERNEL32_GetStringTypeW_4AD180
004AD184 Hi_fp_KERNEL32_SetFilePointerEx_4AD184
004AD188 Hi_fp_KERNEL32_FlushFileBuffers_4AD188
004AD18C Hi_fp_KERNEL32_GetConsoleCP_4AD18C
004AD190 Hi_fp_KERNEL32_SetEndOfFile_4AD190
004AD194 Hi_fp_KERNEL32_GetFileType_4AD194
004AD198 Hi_fp_KERNEL32_SetEnvironmentVariableW_4AD198
004AD19C Hi_fp_KERNEL32_SetEnvironmentVariableA_4AD19C
004AD1A0 Hi_fp_KERNEL32_FreeEnvironmentStringsW_4AD1A0
004AD1A4 Hi_fp_KERNEL32_GetEnvironmentStringsW_4AD1A4
004AD1A8 Hi_fp_KERNEL32_GetCommandLineW_4AD1A8
004AD1AC Hi_fp_KERNEL32_GetCommandLineA_4AD1AC
004AD1B0 Hi_fp_KERNEL32_CreateEventW_4AD1B0
004AD1B4 Hi_fp_KERNEL32_WaitForSingleObjectEx_4AD1B4
004AD1B8 Hi_fp_KERNEL32_ResetEvent_4AD1B8
004AD1BC Hi_fp_KERNEL32_FindNextFileW_4AD1BC
004AD1C0 Hi_fp_KERNEL32_WriteConsoleW_4AD1C0
004AD1C4 Hi_fp_KERNEL32_SetEvent_4AD1C4
004AD1C8 Hi_fp_KERNEL32_LoadLibraryExA_4AD1C8
004AD1CC Hi_fp_KERNEL32_IsDebuggerPresent_4AD1CC
004AD1D0 Hi_fp_KERNEL32_OutputDebugStringW_4AD1D0
004AD1D4 Hi_fp_KERNEL32_EncodePointer_4AD1D4
004AD1D8 Hi_fp_KERNEL32_HeapFree_4AD1D8
004AD1DC Hi_fp_KERNEL32_GetProcessHeap_4AD1DC
004AD1E0 Hi_fp_KERNEL32_InitializeSListHead_4AD1E0
004AD1E4 Hi_fp_KERNEL32_InterlockedPopEntrySList_4AD1E4
004AD1E8 Hi_fp_KERNEL32_InterlockedPushEntrySList_4AD1E8
004AD1EC Hi_fp_KERNEL32_FlushInstructionCache_4AD1EC
004AD1F0 Hi_fp_KERNEL32_IsProcessorFeaturePresent_4AD1F0
004AD1F8 Hi_fp_OLEAUT32_SysFreeString_4AD1F8
004AD1FC Hi_fp_OLEAUT32_VarUI4FromStr_4AD1FC
004AD204 Hi_fp_PSAPI_GetModuleInformation_4AD204
004AD20C Hi_fp_USER32_MessageBoxW_4AD20C
004AD210 Hi_fp_USER32_MessageBoxTimeoutW_4AD210
004AD214 Hi_fp_USER32_KillTimer_4AD214
004AD218 Hi_fp_USER32_SetFocus_4AD218
004AD21C Hi_fp_USER32_GetWindow_4AD21C
004AD220 Hi_fp_USER32_GetWindowLongW_4AD220
004AD224 Hi_fp_USER32_GetMonitorInfoW_4AD224
004AD228 Hi_fp_USER32_GetWindowRect_4AD228
004AD22C Hi_fp_USER32_GetParent_4AD22C
004AD230 Hi_fp_USER32_GetClientRect_4AD230
004AD234 Hi_fp_USER32_MapWindowPoints_4AD234
004AD238 Hi_fp_USER32_SetWindowPos_4AD238
004AD23C Hi_fp_USER32_GetSystemMetrics_4AD23C
004AD240 Hi_fp_USER32_LoadImageW_4AD240
004AD244 Hi_fp_USER32_EnableWindow_4AD244
004AD248 Hi_fp_USER32_SendMessageW_4AD248
004AD24C Hi_fp_USER32_SetWindowTextW_4AD24C
004AD250 Hi_fp_USER32_IsDialogMessageW_4AD250
004AD254 Hi_fp_USER32_GetDlgItem_4AD254
004AD258 Hi_fp_USER32_PostQuitMessage_4AD258
004AD25C Hi_fp_USER32_PostMessageW_4AD25C
004AD260 Hi_fp_USER32_SetTimer_4AD260
004AD264 Hi_fp_USER32_GetWindowTextA_4AD264
004AD268 Hi_fp_USER32_GetWindowTextW_4AD268
004AD26C Hi_fp_USER32_SetWindowLongW_4AD26C
004AD270 Hi_fp_USER32_CreateDialogParamW_4AD270
004AD274 Hi_fp_USER32_UnregisterClassW_4AD274
004AD278 Hi_fp_USER32_DestroyWindow_4AD278
004AD27C Hi_fp_USER32_SetWinEventHook_4AD27C
004AD280 Hi_fp_USER32_DefWindowProcW_4AD280
004AD284 Hi_fp_USER32_PeekMessageW_4AD284
004AD288 Hi_fp_USER32_GetMessageW_4AD288
004AD28C Hi_fp_USER32_TranslateMessage_4AD28C
004AD290 Hi_fp_USER32_DispatchMessageW_4AD290
004AD294 Hi_fp_USER32_ShowWindow_4AD294
004AD298 Hi_fp_USER32_CharNextW_4AD298
004AD29C Hi_fp_USER32_GetWindowLongA_4AD29C
004AD2A0 Hi_fp_USER32_MonitorFromWindow_4AD2A0
004AD2A8 Hi_fp_WINMM_waveOutGetPosition_4AD2A8
004AD2AC Hi_fp_WINMM_waveOutOpen_4AD2AC
004AD2B0 Hi_fp_WINMM_waveOutPrepareHeader_4AD2B0
004AD2B4 Hi_fp_WINMM_waveOutReset_4AD2B4
004AD2B8 Hi_fp_WINMM_waveOutUnprepareHeader_4AD2B8
004AD2BC Hi_fp_WINMM_waveOutWrite_4AD2BC
004AD2C0 Hi_fp_WINMM_waveOutClose_4AD2C0
004AD2C8 Hi_fp_ole32_CoTaskMemRealloc_4AD2C8
004AD2CC Hi_fp_ole32_CoTaskMemAlloc_4AD2CC
004AD2D0 Hi_fp_ole32_CoCreateInstance_4AD2D0
004AD2D4 Hi_fp_ole32_CoInitialize_4AD2D4
004AD2D8 Hi_fp_ole32_CoUninitialize_4AD2D8
004AD2DC Hi_fp_ole32_CoTaskMemFree_4AD2DC
004B3044 Hi_self_cookie
004B37B4 Hi_dllnameArraySize
004B37BC Hi_StartEntryRVA
004B37C0 Hi_VA2
004B37C4 Hi_decxorFourTor
004B37C8 Hi_CntB1h_of_VAM_2C4h_as_dwArray
004B37CC Hi_VA3_for_bwns_SEG
004B37D0 Hi_decxorFourTor_forFuncName
004B37D4 Hi_OFFSET_VA2_to_bwns
004B37D8 Hi_RVA1_for_idata
004B37DC Hi_RVA4
004B37E0 Hi_RVA1_size
004B37E4 Hi_RVA2
004B8690 Hi_Init_for_Hi_VAM1_2C4h_asFuncTable
004B8A20 Hi_Init_kernel_functionPtrs
004B8B00 Hi_get_fp_of_GetProcAddress
004B8BC0 Hi_self_cookie_check
004C38CC Hi_ExitProcess
004C38D0 Hi_VirtualAlloc
004C38D4 Hi_VirtualProtect
004C38D8 Hi_GetModuleHandleA
004C38DC Hi_LoadLibraryA
004C38E0 Hi_GetProcAddress
004C38E4 Hi_VAM1_2C4h_asFuncTable
004C38E8 Hi_initD
004C38EC Hi_init3
004C38F0 Hi_Init7
004C38F4 Hi_curModuleHandle
004C38F8 Hi_StartEntryVA
004B84F3 call Hi_Init_kernel_functionPtrs
函数的调用完成基本核心函数指针的获取工作
.bwns:004B8A4C mov esi, [ebp+loc_hKernel32]
.bwns:004B8A4F call Hi_get_fp_of_GetProcAddress
.bwns:004B8A54 push offset aLoadlibrarya ; "LoadLibraryA"
.bwns:004B8A59 push esi
.bwns:004B8A5A mov ds:Hi_GetProcAddress, eax
.bwns:004B8A5F call eax
.bwns:004B8A61 push offset aGetmodulehandl ; "GetModuleHandleA"
.bwns:004B8A66 push esi
.bwns:004B8A67 mov ds:Hi_LoadLibraryA, eax
.bwns:004B8A6C call ds:Hi_GetProcAddress
.bwns:004B8A72 push offset aVirtualprotect ; "VirtualProtect"
.bwns:004B8A77 push esi
.bwns:004B8A78 mov ds:Hi_GetModuleHandleA, eax
.bwns:004B8A7D call ds:Hi_GetProcAddress
.bwns:004B8A83 push offset aExitprocess ; "ExitProcess"
.bwns:004B8A88 push esi
.bwns:004B8A89 mov ds:Hi_VirtualProtect, eax
.bwns:004B8A8E call ds:Hi_GetProcAddress
.bwns:004B8A94 push offset aVirtualalloc ; "VirtualAlloc"
.bwns:004B8A99 push esi
.bwns:004B8A9A mov ds:Hi_ExitProcess, eax
.bwns:004B8A9F call ds:Hi_GetProcAddress
.bwns:004B8AA5 push 0
.bwns:004B8AA7 mov ds:Hi_VirtualAlloc, eax
.bwns:004B8AAC call ds:Hi_GetModuleHandleA
.bwns:004B8AB2 mov ds:Hi_curModuleHandle, eax
.bwns:004B8AB7 mov eax, ds:Hi_CntB1h_of_VAM_2C4h_as_dwArray
.bwns:004B8ABC push 40h
.bwns:004B8ABE push 3000h
.bwns:004B8AC3 shl eax, 2
.bwns:004B8AC6 push eax
.bwns:004B8AC7 push 0
.bwns:004B8AC9 call ds:Hi_VirtualAlloc
.bwns:004B8ACF pop edi
.bwns:004B8AD0 mov ds:Hi_VAM1_2C4h_asFuncTable, eax
.bwns:004B8AD5 mov ds:Hi_Init7, 7
.bwns:004B8ADF mov ds:Hi_init3, 3
.bwns:004B8AE9 mov ds:Hi_initD, 0Dh
Hi_CntB1h_of_VAM_2C4h_as_dwArray 是导入表被隐藏保护的函数个数
004B8537 call Hi_Init_for_Hi_VAM1_2C4h_asFuncTable
调用完成导入表机制的重构,使用了二级跳板机制,机制内部对函数指针做了加密,
也就导致了直接使用ImportREC是没法完成IAT修复。
al = 0
rb = c_ubyte(0)
xorFourTor = [0x16, 0x0A9, 0xD8, 0x2E]
for i in xrange(0,0x5D):
rb.value = GetOriginalByte(0x4b2aa5+i)
if rb.value == 0:
al = 0
PatchByte(0x4b2aa5+i,rb.value)
else:
rb.value = (rb.value>>2)|(rb.value<<6)
rb.value = rb.value ^ xorFourTor[al&3]
al += 1
rb.value = rb.value ^ al
PatchByte(0x4b2aa5+i,rb.value)
通过上述IDAPython脚本,我们可以得到加密的dll模块名称列表
这里我们是静态分析,动态调试需在在敏感点下断,
否则得不到这些解密的内容,因为完成IAT二级跳机制后,这些模块名称,
也包括后面的函数名称都会被擦除。
.bwns:004B2AA5 aWinmmDll db 'WINMM.dll',0
.bwns:004B2AAF aKernel32Dll_0 db 'KERNEL32.dll',0
.bwns:004B2ABC aUser32Dll db 'USER32.dll',0
.bwns:004B2AC7 aAdvapi32Dll_0 db 'ADVAPI32.dll',0
.bwns:004B2AD4 aOle32Dll db 'ole32.dll',0
.bwns:004B2ADE aOleaut32Dll db 'OLEAUT32.dll',0
.bwns:004B2AEB aComctl32Dll db 'COMCTL32.dll',0
.bwns:004B2AF8 aPsapiDll db 'PSAPI.DLL',0
在 H_VA4 ; 4c6000处,是每个导入函数的描述信息块
每个信息块大小为0x10,共0xB1个导入函数
函数信息块用来加载函数的基本逻辑如下
if FuncInfoBlock.00hb & 1 == 0:
if 0 == hM=GetModuleHandleA(0x4b2aa5+FuncInfoBlock.04hww):
hM=LoadLibraryA(0x4b2aa5+FuncInfoBlock.04hww)
lpszfn = 0x004B2000+FuncInfoBlock.0Chww
xordecfn(lpszfn)
fp = GetProcAddress(hM,lpszfn)
memset(lpszfn,0,len of lpszfn)
else:
if 0 == hM=GetModuleHandleA(0x4b2aa5+FuncInfoBlock.04hww):
hM=LoadLibraryA(0x4b2aa5+FuncInfoBlock.04hww)
fp = GetProcAddress(hM,FuncInfoBlock.00hww >> 1)
FuncInfoBlock{
+00h 若低位为1,则高31位为导入函数的函数索引号
+04h 这个是指向函数所属模块的名称偏移,相对前面的模块列表首地址 004B2AA5 而言
+08h 这个是原IAT函数地址,未加壳时,此指向地址存放导入函数地址
+0Ch 指向以函数名称导入的(+.00hb低位为1时)函数名称在0x004B2000处的偏移
}
def xordecfn(ea):
Hi_decxorFourTor_forFuncName=[0xcd,0x9b,0xc7,0xe4]
al = 0
rb = c_ubyte(0)
while True:
rb.value = GetOriginalByte(ea)
if rb.value == 0:
break
else:
rb.value = (rb.value>>3)|(rb.value<<5)
rb.value = rb.value ^ Hi_decxorFourTor_forFuncName[al&3]
al += 1
rb.value = rb.value ^ al
PatchByte(ea,rb.value)
ea+=1
for i in xrange(0,0xb1):
edi = i*0x10
FuncInfoBlock = 0x4c6000 + edi
mn = GetString(0x4b2aa5+Dword(FuncInfoBlock+0x04),-1,ASCSTR_C)
fn = Dword(FuncInfoBlock)
if (fn&1) != 0:
fn = fn >> 1
print ' 0x{:02X}:"{}[{}]",'.format(i,mn[:-4],fn)
else:
lpszfn = 0x004B2000+Dword(FuncInfoBlock+0x0C)
#print "{}: {:X}".format(mn,lpszfn)
xordecfn(lpszfn)
fn = GetString(lpszfn,-1,ASCSTR_C)
print ' 0x{:02X}:"{}.{}",'.format(i,mn[:-4],fn)
#da_bytes.create_strlit(lpszfn,fn.__len__()+1,0)
通过上述IDAPython脚本我们得以解密得到加壳前原地址表对应的模块函数列表
其中我们对两个函数索引导入的更改为相应名称的形式
这个可以直接用MS编译器工具查询,如
dumpbin /exports oleaut32.dll | find /i " 277 "
dumpbin /exports oleaut32.dll | find /i " 6 "
#0x1C:"OLEAUT32[277]",
0x1C:"OLEAUT32.VarUI4FromStr",
#0x90:"OLEAUT32[6]",
0x90:"OLEAUT32.SysFreeString",
Hi_VAM1_2C4h_asFuncTable={
0x00:"WINMM.waveOutWrite",
0x01:"USER32.GetWindowLongW",
0x02:"USER32.GetClientRect",
0x03:"KERNEL32.CompareStringW",
0x04:"KERNEL32.GetConsoleCP",
0x05:"KERNEL32.GetACP",
0x06:"PSAPI.GetModuleInformation",
0x07:"KERNEL32.DeleteCriticalSection",
0x08:"KERNEL32.InterlockedFlushSList",
0x09:"KERNEL32.InterlockedPushEntrySList",
0x0A:"KERNEL32.IsValidLocale",
0x0B:"ole32.CoUninitialize",
0x0C:"ADVAPI32.RegSetValueExW",
0x0D:"KERNEL32.GetDateFormatW",
0x0E:"KERNEL32.HeapAlloc",
0x0F:"KERNEL32.FindNextFileW",
0x10:"USER32.MessageBoxW",
0x11:"KERNEL32.GetThreadContext",
0x12:"KERNEL32.LCMapStringW",
0x13:"KERNEL32.SetStdHandle",
0x14:"KERNEL32.GetModuleFileNameA",
0x15:"KERNEL32.FindFirstFileExA",
0x16:"WINMM.waveOutOpen",
0x17:"KERNEL32.CreateFileW",
0x18:"KERNEL32.GetCommandLineA",
0x19:"KERNEL32.GetModuleHandleW",
0x1A:"KERNEL32.RtlUnwind",
0x1B:"KERNEL32.MultiByteToWideChar",
#0x1C:"OLEAUT32[277]",
0x1C:"OLEAUT32.VarUI4FromStr",
0x1D:"KERNEL32.ReadFile",
0x1E:"KERNEL32.GetFileType",
0x1F:"USER32.SetWindowTextW",
0x20:"KERNEL32.InterlockedIncrement",
0x21:"KERNEL32.ResetEvent",
0x22:"USER32.GetParent",
0x23:"KERNEL32.FindResourceW",
0x24:"KERNEL32.GetConsoleMode",
0x25:"KERNEL32.IsDebuggerPresent",
0x26:"KERNEL32.VirtualFree",
0x27:"USER32.MessageBoxTimeoutW",
0x28:"KERNEL32.EnterCriticalSection",
0x29:"KERNEL32.RaiseException",
0x2A:"KERNEL32.GetTimeFormatW",
0x2B:"KERNEL32.WaitForSingleObject",
0x2C:"KERNEL32.IsProcessorFeaturePresent",
0x2D:"KERNEL32.lstrcatA",
0x2E:"USER32.ShowWindow",
0x2F:"KERNEL32.TlsFree",
0x30:"KERNEL32.VirtualAlloc",
0x31:"KERNEL32.GetStdHandle",
0x32:"KERNEL32.InitializeSListHead",
0x33:"KERNEL32.CreateFileA",
0x34:"KERNEL32.ExitProcess",
0x35:"USER32.DefWindowProcW",
0x36:"KERNEL32.WriteFile",
0x37:"KERNEL32.SetEvent",
0x38:"KERNEL32.InitializeCriticalSection",
0x39:"KERNEL32.LoadResource",
0x3A:"KERNEL32.SetFilePointer",
0x3B:"USER32.DestroyWindow",
0x3C:"USER32.GetWindow",
0x3D:"ole32.CoTaskMemRealloc",
0x3E:"USER32.PostMessageW",
0x3F:"ole32.CoInitialize",
0x40:"USER32.KillTimer",
0x41:"KERNEL32.GetCPInfo",
0x42:"WINMM.waveOutGetPosition",
0x43:"USER32.SendMessageW",
0x44:"KERNEL32.HeapDestroy",
0x45:"KERNEL32.HeapFree",
0x46:"KERNEL32.FreeLibrary",
0x47:"KERNEL32.SetEndOfFile",
0x48:"ole32.CoCreateInstance",
0x49:"KERNEL32.GetProcessHeap",
0x4A:"ole32.CoTaskMemFree",
0x4B:"USER32.IsDialogMessageW",
0x4C:"USER32.PostQuitMessage",
0x4D:"ole32.CoTaskMemAlloc",
0x4E:"KERNEL32.InterlockedPopEntrySList",
0x4F:"KERNEL32.IsValidCodePage",
0x50:"ADVAPI32.RegOpenKeyExW",
0x51:"KERNEL32.GetSystemTimeAsFileTime",
0x52:"USER32.CreateDialogParamW",
0x53:"KERNEL32.OutputDebugStringA",
0x54:"USER32.TranslateMessage",
0x55:"KERNEL32.ReadConsoleW",
0x56:"KERNEL32.GetCurrentThread",
0x57:"KERNEL32.lstrcmpiW",
0x58:"KERNEL32.WaitForSingleObjectEx",
0x59:"KERNEL32.GetUserDefaultLangID",
0x5A:"USER32.SetWindowLongW",
0x5B:"KERNEL32.GetCurrentProcess",
0x5C:"KERNEL32.TlsGetValue",
0x5D:"WINMM.waveOutReset",
0x5E:"KERNEL32.GetStringTypeW",
0x5F:"KERNEL32.FlushFileBuffers",
0x60:"USER32.MapWindowPoints",
0x61:"USER32.GetWindowTextA",
0x62:"KERNEL32.SetUnhandledExceptionFilter",
0x63:"KERNEL32.EncodePointer",
0x64:"KERNEL32.SetLastError",
0x65:"KERNEL32.GetModuleFileNameW",
0x66:"KERNEL32.SetEnvironmentVariableA",
0x67:"ADVAPI32.RegDeleteKeyW",
0x68:"KERNEL32.TlsSetValue",
0x69:"USER32.MonitorFromWindow",
0x6A:"USER32.LoadImageW",
0x6B:"KERNEL32.OutputDebugStringW",
0x6C:"ADVAPI32.RegCreateKeyExW",
0x6D:"WINMM.waveOutClose",
0x6E:"USER32.UnregisterClassW",
0x6F:"KERNEL32.SetThreadPriority",
0x70:"USER32.CharNextW",
0x71:"ADVAPI32.RegEnumKeyExW",
0x72:"KERNEL32.GetOEMCP",
0x73:"KERNEL32.FindClose",
0x74:"KERNEL32.GetModuleHandleExW",
0x75:"USER32.GetMonitorInfoW",
0x76:"KERNEL32.FindResourceA",
0x77:"USER32.SetTimer",
0x78:"KERNEL32.HeapCreate",
0x79:"KERNEL32.DecodePointer",
0x7A:"KERNEL32.lstrlenA",
0x7B:"USER32.GetWindowTextW",
0x7C:"KERNEL32.UnhandledExceptionFilter",
0x7D:"KERNEL32.LoadLibraryExW",
0x7E:"KERNEL32.LoadLibraryExA",
0x7F:"KERNEL32.HeapSize",
0x80:"KERNEL32.FlushInstructionCache",
0x81:"KERNEL32.WriteConsoleW",
0x82:"KERNEL32.CloseHandle",
0x83:"KERNEL32.SetEnvironmentVariableW",
0x84:"USER32.GetWindowLongA",
0x85:"KERNEL32.GetEnvironmentStringsW",
0x86:"KERNEL32.CreateEventW",
0x87:"ADVAPI32.RegQueryInfoKeyW",
0x88:"ADVAPI32.RegCloseKey",
0x89:"USER32.GetSystemMetrics",
0x8A:"KERNEL32.SizeofResource",
0x8B:"KERNEL32.GetCurrentThreadId",
0x8C:"USER32.SetFocus",
0x8D:"KERNEL32.FindFirstFileExW",
0x8E:"KERNEL32.GetStartupInfoW",
0x8F:"KERNEL32.SetFilePointerEx",
#0x90:"OLEAUT32[6]",
0x90:"OLEAUT32.SysFreeString",
0x91:"KERNEL32.SetConsoleCtrlHandler",
0x92:"KERNEL32.EnumSystemLocalesW",
0x93:"USER32.PeekMessageW",
0x94:"USER32.DispatchMessageW",
0x95:"WINMM.waveOutUnprepareHeader",
0x96:"KERNEL32.InterlockedDecrement",
0x97:"KERNEL32.Sleep",
0x98:"KERNEL32.TlsAlloc",
0x99:"ADVAPI32.RegDeleteValueW",
0x9A:"KERNEL32.HeapReAlloc",
0x9B:"WINMM.waveOutPrepareHeader",
0x9C:"KERNEL32.GetUserDefaultLCID",
0x9D:"KERNEL32.InitializeCriticalSectionAndSpinCount",
0x9E:"KERNEL32.LeaveCriticalSection",
0x9F:"USER32.EnableWindow",
0xA0:"USER32.SetWindowPos",
0xA1:"KERNEL32.GetCommandLineW",
0xA2:"KERNEL32.WideCharToMultiByte",
0xA3:"USER32.SetWinEventHook",
0xA4:"KERNEL32.GetProcAddress",
0xA5:"KERNEL32.GetLocaleInfoW",
0xA6:"KERNEL32.QueryPerformanceCounter",
0xA7:"KERNEL32.FreeEnvironmentStringsW",
0xA8:"COMCTL32.InitCommonControlsEx",
0xA9:"KERNEL32.TerminateProcess",
0xAA:"KERNEL32.GetLastError",
0xAB:"USER32.GetMessageW",
0xAC:"KERNEL32.FindNextFileA",
0xAD:"KERNEL32.GetCurrentProcessId",
0xAE:"USER32.GetWindowRect",
0xAF:"USER32.GetDlgItem",
0xB0:"KERNEL32.CreateThread",}
进一步,我们可以直接完成导入表函数的IDA自动重命名
for i in xrange(0,0xb1):
edi = i*0x10
FuncInfoBlock = 0x4c6000 + edi
VA = 0x400000 + Dword(FuncInfoBlock+0x08)
print "{:X} {}".format(VA,Hi_VAM1_2C4h_asFuncTable[i])
MakeName(VA,"Hi_fp_{}_{:X}".format(Hi_VAM1_2C4h_asFuncTable[i].replace('.','_'),VA))
二级跳的导入函数机制如下
正常情况下.idata:004AD160 extrn QueryPerformanceCounter
处会存放导入函数QueryPerformanceCounter的地址,
在加壳的情况下,其存放的是混淆code-chip:VA20h1
VA20h1由VirtualAlloc动态分配,其存放下面VA20h1内容,
留意到XorEncAdd01字段存放的又是另一个code-chip:VA20h2的加密地址
加密方式是code-chip:VA20h2地址与0x20170619异或,
而code-chip:VA20h1代码就是负责解密调用code-chip:VA20h2;
在code-chip:VA20h2中,注意到XorEncAdd02字段,这里既是导入函数地址
的加密信息,由导入函数地址与0x19890526异或加密得到,code-chip:VA20h2
任务就是完成导入函数地址解密调用,举例如下
VA20h2
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
E8 01 00 00 00 E9 58 EB 01 E8 B8 XorEncAdd02 EB //XorEncAdd02=fp ^ 0x19890526
01 15 35|26 05 89 19 EB 01 FF 50 EB 02 FF 15 C3
VA20h1
E8 01 00 00 00 E9 58 EB 01 E8 B8 XorEncAdd01 EB //XorEncAdd01=VA20h2 ^ 0x20170619
01 15 35|19 06 17 20 EB 01 FF 50 EB 02 FF 15 C3
Hi_VAM1_2C4h[dwIdx]=VA20h1
如在程序的真正入口 0x4442a2 处断下,我们观察导入表QueryPerformanceCounter函数的信息,
其存放的是03650000,即QueryPerformanceCounter函数的code-chip:VA20h1,
我们将混淆去掉后如下所示,其就是解密XorEncAdd01=23710619 得到 03660000 跳转到
QueryPerformanceCounter函数的code-chip:VA20h2,接着就是
解密XorEncAdd01=6CE05A86 得到 QueryPerformanceCounter的地址跳转
.idata:004AD160 extrn QueryPerformanceCounter
QueryPerformanceCounter函数的code-chip:VA20h1
03650000 E8 01000000 CALL 03650006
03650005 90 NOP
03650006 58 POP EAX
03650007 EB 01 JMP SHORT 0365000A
03650009 90 NOP
0365000A B8 19067123 MOV EAX,23710619
0365000F EB 01 JMP SHORT 03650012
03650011 90 NOP
03650012 35 19061720 XOR EAX,20170619
03650017 EB 01 JMP SHORT 0365001A
03650019 90 NOP
0365001A 50 PUSH EAX
0365001B EB 02 JMP SHORT 0365001F
0365001D 90 NOP
0365001E 90 NOP
0365001F C3 RETN
QueryPerformanceCounter函数的code-chip:VA20h2
03660000
03660000 E8 01000000 CALL 03660006
03660005 90 NOP
03660006 58 POP EAX
03660007 EB 01 JMP SHORT 0366000A
03660009 90 NOP
0366000A B8 865AE06C MOV EAX,6CE05A86
0366000F EB 01 JMP SHORT 03660012
03660011 90 NOP
03660012 35 26058919 XOR EAX,19890526
03660017 EB 01 JMP SHORT 0366001A
03660019 90 NOP
0366001A 50 PUSH EAX
0366001B EB 02 JMP SHORT 0366001F
0366001D 90 NOP
0366001E 90 NOP
0366001F C3 RETN
既要修复导入表,我们需将
.idata:004AD160 extrn QueryPerformanceCounter
处的code-chip:VA20h1地址替换为真实的QueryPerformanceCounter地址
我们通过IDAPython脚本生成自动修复的OD Script脚本
for i in xrange(0,0xb1):
edi = i*0x10
FuncInfoBlock = 0x4c6000 + edi
VA = 0x400000 + Dword(FuncInfoBlock+0x08)
mf = Hi_VAM1_2C4h_asFuncTable[i].split('.')
print 'gpa "{}", "{}.dll"'.format(mf[1],mf[0])
print 'mov [{:X}],$RESULT'.format(VA)
OD Script 脚本如下
gpa "waveOutWrite", "WINMM.dll"
mov [4AD2BC],$RESULT
gpa "GetWindowLongW", "USER32.dll"
mov [4AD220],$RESULT
...
gpa "CreateThread", "KERNEL32.dll"
mov [4AD0AC],$RESULT
;gpa "p", "p.dll"
;mov [4AD2E4],$RESULT
注意到最后的
;gpa "p", "p.dll"
;mov [4AD2E4],$RESULT
我们通过//cl /EHsc p.cpp /link /DEF:p.def /DLL /OUT:p.dll编译命令得到
一个导出p函数的p模块,p函数为空操作 retn
用于修复一下函数调用
.idata:004AD2E4 off_4AD2E4 dd offset nullsub_8
.text:0044493A nullsub_8 proc near
.text:0044493A retn
.text:4493A nullsub_8 endp
由于最终off_4AD2E4还用于保护检测,所以完成修复后,还需将setnz al,修改为 setz al,
即用CFF Explorer 将0F 95 C0 修改为0F 94 C0
.text:0044493B __guard_icall_checks_enforced:
.text:0044493B 8B 0D E4 D2 4A 00 mov ecx, ds:__imp_p
.text:00444941 33 C0 xor eax, eax
.text:00444943 81 F9 3A 49 44 00 cmp ecx, offset nullsub_25
.text:00444949 0F 95 C0 setnz al
.text:0044494C C3 retn
文件名 p.cpp
#include <windows.h>
void p(void){;} //for CFF add importer
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
break ;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
文件名fileName p.def
LIBRARY p
EXPORTS
p @1
有了上述OD Script脚本和p.dll,我们就可以尝试脱壳
先用CFF Explorer 将p.dll模块添加到样例中,让程序启动时自动加载p模块
也可以用OD Script加载p模块的方式
然后我们断在入口点4442A2
运行上述OD Script 脚本修复IAT,然后dump出程序CTF09.exe
紧接着用Import REC附加被OD调试的样例
在IAT Infos needed处
设置 OEP 000442A2
设置 RVA 000AD000
然后Get Imports获取导入表
导入表由于模块间代理导入等原因,会出现NO的情形,
这时候我们只需对照我们已经重命名的IDA中的导入函数信息修正即可
如ImportREC提示的下述地址的导入表函数并不是ole32模块的相应函数
这时,我们只需对照我们上述得到的下述模块函数信息修正即可
.idata:004AD2CC Hi_fp_ole32_CoTaskMemAlloc_4AD2CC dd 0 ; .text:00413E8C↑r ...
.idata:004AD2D0 Hi_fp_ole32_CoCreateInstance_4AD2D0 dd 0
.idata:004AD2D4 Hi_fp_ole32_CoInitialize_4AD2D4 dd 0
.idata:004AD2D8 Hi_fp_ole32_CoUninitialize_4AD2D8 dd 0
.idata:004AD2DC Hi_fp_ole32_CoTaskMemFree_4AD2DC dd
修正Imported Function Found信息后,在New Import Infos设置项里,
我们设置RVA AD000,选中Add new secio
最后fix Dump选择OD dump出的样例 CTF09.exe进行修复。
至此,再把修复的放进另一个IDA里进行分析或调试,就清净多了。
也即算完成壳的初步脱去。