Created
April 18, 2015 02:48
-
-
Save mesaleh/076871f4fb80e7530feb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <class T> // T: PIMAGE_THUNK_DATA64 or PIMAGE_THUNK_DATA32 | |
vector<string> PE::getModuleAPIs(T pThunk, PIMAGE_SECTION_HEADER IT) | |
{ | |
vector<string> APIs; | |
// check if IMAGE_THUNK_DATA is within the section of Import directory, otherwise, most likely the file is packed or manualy manipulated. | |
if (((DWORD)pThunk < ((DWORD)LoadAddr + IT->PointerToRawData)) || ((DWORD)pThunk >((DWORD)LoadAddr + IT->PointerToRawData + IT->SizeOfRawData))) { | |
Suspicious |= SUSPICIOUS_IMPORTS; | |
} | |
// check if IMAGE_THUNK_DATA points out of file boundaries. | |
if (((DWORD)pThunk < ((DWORD)LoadAddr)) || ( ((DWORD)pThunk + sizeof(*pThunk)) > ((DWORD)LoadAddr + FileSize)) ) { | |
Suspicious |= CORRUPTED_IMPORTS; | |
return APIs; | |
} | |
ULONGLONG iIMAGE_ORDINAL_FLAG; | |
if(isPE64()) | |
iIMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG64; | |
else | |
iIMAGE_ORDINAL_FLAG = IMAGE_ORDINAL_FLAG32; | |
if(pThunk->u1.Ordinal & iIMAGE_ORDINAL_FLAG) fImportByOrdinal = true; | |
while(pThunk->u1.Ordinal) | |
{ | |
string API; | |
// if import by name | |
if(!(pThunk->u1.Ordinal & iIMAGE_ORDINAL_FLAG)) { | |
// Yup, ApiNameOffset is DWORD, 32bit, for both 32bit and 64bit executables, assuming we've not yet seen an 64bit executable > 4GB. | |
DWORD ApiNameOffset = getOffsetFromRva(pThunk->u1.AddressOfData) + FIELD_OFFSET(IMAGE_IMPORT_BY_NAME, Name); | |
// within file boundaries ? | |
if (ApiNameOffset > FileSize) { | |
Suspicious |= CORRUPTED_IMPORTS; | |
} | |
else { | |
DWORD i = ApiNameOffset; | |
while (i < FileSize && LoadAddr[i] != 0 && (i - ApiNameOffset < MAX_API_NAME)) i++; // There is no unallowed chars for API name. | |
/* | |
* There are three cases here: | |
* | |
* 1- If the size = MAX_API_NAME, Win loader's RtlInitString() will take the first MAX_API_NAME name regardless of the "real" size. That would be the API that will be looked for. | |
* 2- If the Name was shorter that MAX_API_NAME but passes the file size, most likely the memory location at the offset "file size" | |
* will be 0, so the loader will read the zero and terminates the string. | |
* Unless in very rare condition that the file ends exactly at the boundary of a memory page and accessing next page will fire an exception. | |
* For those two cases, we'll get the string up until the boundary, MAX_API_NAME or FileSize. | |
* 3- The file we're scanning is a good file that respects itself and has a normal API name, which is a case we don't usually encounter when dealing with malware :) | |
*/ | |
if ((i >= FileSize) || (i - ApiNameOffset >= MAX_API_NAME)) | |
Suspicious |= SUSPICIOUS_IMPORTS; | |
API = string((char*) &LoadAddr[ApiNameOffset], i - ApiNameOffset); | |
} | |
} | |
// else if import by ordinal | |
else { | |
int n = pThunk->u1.Ordinal & 0x00FF; // get ordinal number | |
API = "Ord(" + numToStr(n) + ")"; | |
} | |
APIs.push_back(API); | |
pThunk++; | |
} | |
return APIs; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment