VirusTotal / yara

The pattern matching swiss knife
https://virustotal.github.io/yara/
BSD 3-Clause "New" or "Revised" License
8.31k stars 1.45k forks source link

yara imphash and pefile imphash are different #1943

Closed syyoo84 closed 1 year ago

syyoo84 commented 1 year ago

Describe the bug yara imphash and pefile imphash are different So you can't use imphash in yara rule. Any reason? sha256: 803d740df04cc995fd7010473be6b06e190c7ca5114a525d951ae11e7394ab12 yara imphash: ecb1f45f310c2bf07612a019ce157b0f pefile imphash: b22fdcce4de8993adbff1ff244d1b4a5 https://www.virustotal.com/gui/file/803d740df04cc995fd7010473be6b06e190c7ca5114a525d951ae11e7394ab12/details

To Reproduce Steps to reproduce the behavior:

Expected behavior A clear and concise description of what you expected to happen.

Screenshots If applicable, add screenshots to help explain your problem.

Please complete the following information:

Additional context Add any other context about the problem here.

wxsBSD commented 1 year ago

Great find! I'm pretty sure this has been broken since I first implemented imphash in YARA back in 2014. I based it off the Mandiant blog post, which I'm pretty sure did not say anything about this case. Turns out the pefile code has been ignoring names that are empty strings, or otherwise evaluate to false in python, for at least the last 10 years (according to blame): https://github.com/erocarrera/pefile/blob/593d094e35198dad92aaf040bef17eb800c8a373/pefile.py#L5871-L5872

I've put up a fix for this along with a test case so we shouldn't regress on it in the future either.

syyoo84 commented 1 year ago

Great find! I'm pretty sure this has been broken since I first implemented imphash in YARA back in 2014. I based it off the Mandiant blog post, which I'm pretty sure did not say anything about this case. Turns out the pefile code has been ignoring names that are empty strings, or otherwise evaluate to false in python, for at least the last 10 years (according to blame): https://github.com/erocarrera/pefile/blob/593d094e35198dad92aaf040bef17eb800c8a373/pefile.py#L5871-L5872

I've put up a fix for this along with a test case so we shouldn't regress on it in the future either.

Here's another case. If the IAT function name contains null bytes as well as a ' mark, it is ignored and an imphash hash is judged to be created. So yara imphash and pefile imphash are different. https://www.virustotal.com/gui/file/10fdf28e81f443299fb2753fa06065d2913d8275a322f27556728e6db32510e7/detai

import_details [0] library_name = "KERNEL32.dll" number_of_functions = 91 functions [0] rva = 4120 ordinal = YR_UNDEFINED name = "FoldStringW" [1] rva = 4124 ordinal = YR_UNDEFINED name = "SetWaitaleTimer" [2] rva = 4128 ordinal = YR_UNDEFINED name = "WaitNamedPipeA" [3] rva = 4132 ordinal = YR_UNDEFINED name = "\x98omm\x98onfigDialogW" [4] rva = 4136 ordinal = YR_UNDEFINED name = "SetSystemTimeAdjustment" [5] rva = 4140 ordinal = YR_UNDEFINED name = "SearchPathA" [6] rva = 4144 ordinal = YR_UNDEFINED name = "EnumResourceTypesA" [7] rva = 4148 ordinal = YR_UNDEFINED name = "Get\x98PInfoExA" [8] rva = 4152 ordinal = YR_UNDEFINED name = "EnumResourceTypesW" [9] rva = 4156 ordinal = YR_UNDEFINED name = "GetModuleFileNameA" [10] rva = 4160 ordinal = YR_UNDEFINED name = "Write\x98onsoleOutput\x98haracterW" [11] rva = 4164 ordinal = YR_UNDEFINED name = "Get\x98onsoleAliasesLengthA" [12] rva = 4168 ordinal = YR_UNDEFINED name = "DeleteFileA" [13] rva = 4172 ordinal = YR_UNDEFINED name = "Fill\x98onsoleOutput\x98haracterW" [14] rva = 4176 ordinal = YR_UNDEFINED name = "D\x03LocalAlloc" [15] rva = 4180 ordinal = YR_UNDEFINED name = "GetProcAddress" [16] rva = 4184 ordinal = YR_UNDEFINED name = "GetModuleHandleW" [17] rva = 4188 ordinal = YR_UNDEFINED name = "LoadLiraryW" [18] rva = 4192 ordinal = YR_UNDEFINED name = "AddRefAct\x98tx" [19] rva = 4196 ordinal = YR_UNDEFINED name = "Get\x98onsoleAliasW" [20] rva = 4200 ordinal = YR_UNDEFINED name = "FindFirst\x98hangeNotificationA" [21] rva = 4204 ordinal = YR_UNDEFINED name = "WritePrivateProfileStringW" [22] rva = 4208 ordinal = YR_UNDEFINED name = "EnumResourceNamesA" [23] rva = 4212 ordinal = YR_UNDEFINED name = "lstrcpynA" [24] rva = 4216 ordinal = YR_UNDEFINED name = "AddAtomA" [25] rva = 4220 ordinal = YR_UNDEFINED name = "Get\x98onsoleAliasesLengthW" [26] rva = 4224 ordinal = YR_UNDEFINED name = "Free\x98onsole" [27] rva = 4228 ordinal = YR_UNDEFINED name = "asesLengthW" [28] rva = 4232 ordinal = YR_UNDEFINED name = "FindNextFileW" [29] rva = 4236 ordinal = YR_UNDEFINED name = "SetPriority\x98lass" [30] rva = 4240 ordinal = YR_UNDEFINED name = "Build\x98ommD\x98BAndTimeoutsW" [31] rva = 4244 ordinal = YR_UNDEFINED name = "OpenJoOjectW" [32] rva = 4248 ordinal = YR_UNDEFINED name = "t\x98omputerNameExW" [33] rva = 4252 ordinal = YR_UNDEFINED name = "FindResourceExW" [34] rva = 4256 ordinal = YR_UNDEFINED name = "Set\x98onsoleMode" [35] rva = 4260 ordinal = YR_UNDEFINED name = "_lclose" [36] rva = 4264 ordinal = YR_UNDEFINED name = "Set\x98ommMask" [37] rva = 4268 ordinal = YR_UNDEFINED name = "Get\x98onsoleTitleW" [38] rva = 4272 ordinal = YR_UNDEFINED name = "\x98reateDirectoryExA" [39] rva = 4276 ordinal = YR_UNDEFINED name = "HeapAlloc" [40] rva = 4280 ordinal = YR_UNDEFINED name = "HeapSize" [41] rva = 4284 ordinal = YR_UNDEFINED name = "HeapReAlloc" [42] rva = 4288 ordinal = YR_UNDEFINED name = "Get\x98ommandLineW" [43] rva = 4292 ordinal = YR_UNDEFINED name = "HeapSetInformation" [44] rva = 4296 ordinal = YR_UNDEFINED name = "GetStartupInfoW" [45] rva = 4300 ordinal = YR_UNDEFINED name = "IsProcessorFeaturePresent" [46] rva = 4304 ordinal = YR_UNDEFINED name = "EncodePointer" [47] rva = 4308 ordinal = YR_UNDEFINED name = "SetUnhandledExceptionFilter" [48] rva = 4312 ordinal = YR_UNDEFINED name = "ExitProcess" [49] rva = 4316 ordinal = YR_UNDEFINED name = "DecodePointer" [50] rva = 4320 ordinal = YR_UNDEFINED name = "WriteFile" [51] rva = 4324 ordinal = YR_UNDEFINED name = "GetStdHandle" [52] rva = 4328 ordinal = YR_UNDEFINED name = "GetModuleFileNameW" [53] rva = 4332 ordinal = YR_UNDEFINED name = "FreeEnvironmentStringsW" [54] rva = 4336 ordinal = YR_UNDEFINED name = "GetEnvironmentStringsW" [55] rva = 4340 ordinal = YR_UNDEFINED name = "SetHandle\x98ount" [56] rva = 4344 ordinal = YR_UNDEFINED name = "Initialize\x98riticalSectionAndSpin\x98ount" [57] rva = 4348 ordinal = YR_UNDEFINED name = "GetFileType" [58] rva = 4352 ordinal = YR_UNDEFINED name = "Delete\x98riticalSection" [59] rva = 4356 ordinal = YR_UNDEFINED name = "TlsAlloc" [60] rva = 4360 ordinal = YR_UNDEFINED name = "TlsGetValue" [61] rva = 4364 ordinal = YR_UNDEFINED name = "TlsSetValue" [62] rva = 4368 ordinal = YR_UNDEFINED name = "TlsFree" [63] rva = 4372 ordinal = YR_UNDEFINED name = "InterlockedIncrement" [64] rva = 4376 ordinal = YR_UNDEFINED name = "SetLastError" [65] rva = 4380 ordinal = YR_UNDEFINED name = "Get\x98urrentThreadId" [66] rva = 4384 ordinal = YR_UNDEFINED name = "GetLastError" [67] rva = 4388 ordinal = YR_UNDEFINED name = "InterlockedDecrement" [68] rva = 4392 ordinal = YR_UNDEFINED name = "Heap\x98reate" [69] rva = 4396 ordinal = YR_UNDEFINED name = "QueryPerformance\x98ounter" [70] rva = 4400 ordinal = YR_UNDEFINED name = "GetTick\x98ount" [71] rva = 4404 ordinal = YR_UNDEFINED name = "Get\x98urrentProcessId" [72] rva = 4408 ordinal = YR_UNDEFINED name = "GetSystemTimeAsFileTime" [73] rva = 4412 ordinal = YR_UNDEFINED name = "Get\x98PInfo" [74] rva = 4416 ordinal = YR_UNDEFINED name = "GetA\x98P" [75] rva = 4420 ordinal = YR_UNDEFINED name = "GetOEM\x98P" [76] rva = 4424 ordinal = YR_UNDEFINED name = "IsValid\x98odePage" [77] rva = 4428 ordinal = YR_UNDEFINED name = "UnhandledExceptionFilter" [78] rva = 4432 ordinal = YR_UNDEFINED name = "IsDeuggerPresent" [79] rva = 4436 ordinal = YR_UNDEFINED name = "TerminateProcess" [80] rva = 4440 ordinal = YR_UNDEFINED name = "Get\x98urrentProcess" [81] rva = 4444 ordinal = YR_UNDEFINED name = "Leave\x98riticalSection" [82] rva = 4448 ordinal = YR_UNDEFINED name = "Enter\x98riticalSection" [83] rva = 4452 ordinal = YR_UNDEFINED name = "n" [84] rva = 4456 ordinal = YR_UNDEFINED name = "Sleep" [85] rva = 4460 ordinal = YR_UNDEFINED name = "RtlUnwind" [86] rva = 4464 ordinal = YR_UNDEFINED name = "RaiseException" [87] rva = 4468 ordinal = YR_UNDEFINED name = "Wide\x98harToMultiByte" [88] rva = 4472 ordinal = YR_UNDEFINED name = "L\x98MapStringW" [89] rva = 4476 ordinal = YR_UNDEFINED name = "MultiByteToWide\x98har" [90] rva = 4480 ordinal = YR_UNDEFINED name = "GetStringTypeW" [1] library_name = "USER32.dll" number_of_functions = 2 functions [0] rva = 4488 ordinal = YR_UNDEFINED name = "\x98lientToScreen" [1] rva = 4492 ordinal = YR_UNDEFINED name = "ScreenTo\x98lient" [2] library_name = "ADVAPI32.dll" number_of_functions = 4 functions [0] rva = 4096 ordinal = YR_UNDEFINED name = "\x98loseEventLog" [1] rva = 4100 ordinal = YR_UNDEFINED name = "DeregisterEventSource" [2] rva = 4104 ordinal = YR_UNDEFINED name = "GetNumerOfEventLogRecords" [3] rva = 4108 ordinal = YR_UNDEFINED name = "GetEventLogInformation" [3] library_name = "WINHTTP.dll" number_of_functions = 2 functions [0] rva = 4500 ordinal = YR_UNDEFINED name = "WinHttpSetTimeouts" [1] rva = 4504 ordinal = YR_UNDEFINED name = "WinHttpReadData"

wxsBSD commented 1 year ago

Ok, I'll take a look in a bit. Thanks for bringing it up!

wxsBSD commented 1 year ago

Thanks for pointing these out! I've updated the PR to reflect this and I think we are now aligned with pefile (which I would argue is the definitive implementation of imphash and import parsing we should try to align with).

syyoo84 commented 1 year ago

Thank you for your support. Thank you for being able to contribute to the Yara community by reporting bugs at NSHC Threat Research Lab.