Page Menu
Home
desp's stash
Search
Configure Global Search
Log In
Files
F368909
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
169 KB
Subscribers
None
View Options
diff --git a/Scylla/ApiReader.cpp b/Scylla/ApiReader.cpp
index 3975f31..9133f4d 100644
--- a/Scylla/ApiReader.cpp
+++ b/Scylla/ApiReader.cpp
@@ -1,1325 +1,1325 @@
#include "ApiReader.h"
#include "Scylla.h"
#include "Architecture.h"
#include "SystemInformation.h"
+#include "StringConversion.h"
-stdext::hash_multimap<DWORD_PTR, ApiInfo *> ApiReader::apiList; //api look up table
+std::unordered_map<DWORD_PTR, ApiInfo *> ApiReader::apiList; //api look up table
std::map<DWORD_PTR, ImportModuleThunk> * ApiReader::moduleThunkList; //store found apis
DWORD_PTR ApiReader::minApiAddress = 0xFFFFFFFF;
DWORD_PTR ApiReader::maxApiAddress = 0;
//#define DEBUG_COMMENTS
void ApiReader::readApisFromModuleList()
{
for (unsigned int i = 0; i < moduleList.size();i++)
{
setModulePriority(&moduleList[i]);
if (moduleList[i].modBaseAddr + moduleList[i].modBaseSize > maxValidAddress)
{
maxValidAddress = moduleList[i].modBaseAddr + moduleList[i].modBaseSize;
}
Scylla::windowLog.log(L"Module parsing: %s",moduleList[i].fullPath);
if (!moduleList[i].isAlreadyParsed)
{
parseModule(&moduleList[i]);
}
}
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Address Min " PRINTF_DWORD_PTR_FULL L" Max " PRINTF_DWORD_PTR_FULL L"\nimagebase " PRINTF_DWORD_PTR_FULL L" maxValidAddress " PRINTF_DWORD_PTR_FULL, minApiAddress, maxApiAddress, targetImageBase ,maxValidAddress);
#endif
}
void ApiReader::parseModule(ModuleInfo *module)
{
module->parsing = true;
if (isWinSxSModule(module))
{
parseModuleWithMapping(module);
}
else if (isModuleLoadedInOwnProcess(module))
{
parseModuleWithOwnProcess(module);
}
else
{
parseModuleWithProcess(module);
}
module->isAlreadyParsed = true;
}
void ApiReader::parseModuleWithMapping(ModuleInfo *moduleInfo)
{
LPVOID fileMapping = 0;
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
fileMapping = createFileMappingViewRead(moduleInfo->fullPath);
if (fileMapping == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)fileMapping;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileMapping + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
parseExportTable(moduleInfo, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)fileMapping + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)fileMapping);
}
UnmapViewOfFile(fileMapping);
}
inline bool ApiReader::isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader)
{
if ((rva > pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) && (rva < (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)))
{
return true;
}
else
{
return false;
}
}
void ApiReader::handleForwardedApi(DWORD_PTR vaStringPointer,char * functionNameParent, DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent)
{
size_t dllNameLength = 0;
WORD ordinal = 0;
ModuleInfo *module = 0;
DWORD_PTR vaApi = 0;
DWORD_PTR rvaApi = 0;
char dllName[100] = {0};
WCHAR dllNameW[100] = {0};
char *fordwardedString = (char *)vaStringPointer;
char *searchFunctionName = strchr(fordwardedString, '.');
if (!searchFunctionName)
return;
dllNameLength = searchFunctionName - fordwardedString;
if (dllNameLength >= 99)
{
return;
}
else
{
strncpy_s(dllName,sizeof(dllName),fordwardedString,dllNameLength);
}
searchFunctionName++;
//Windows 7
if (!strncmp(dllName,"api-ms-win-", 11))
{
/*
Info: http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html
*/
FARPROC addy = GetProcAddress(GetModuleHandleA(dllName), searchFunctionName);
if (addy != 0)
{
addApi(functionNameParent,0, ordinalParent, (DWORD_PTR)addy, (DWORD_PTR)addy - (DWORD_PTR)GetModuleHandleA(dllName), true, moduleParent);
}
return;
}
- strcat_s(dllName,sizeof(dllName),".dll");
+ strcat_s(dllName, sizeof(dllName), ".dll");
- size_t convertedChars = 0;
- mbstowcs_s(&convertedChars, dllNameW, strlen(dllName) + 1, dllName, _TRUNCATE);
+ StringConversion::ToUTF16(dllName, dllNameW, _countof(dllNameW));
if (!_wcsicmp(dllNameW, moduleParent->getFilename()))
{
module = moduleParent;
}
else
{
module = findModuleByName(dllNameW);
}
if (module != 0) // module == 0 -> can be ignored
{
/*if ((module->isAlreadyParsed == false) && (module != moduleParent))
{
//do API extract
if (module->parsing == true)
{
//some stupid circle dependency
printf("stupid circle dependency %s\n",module->getFilename());
}
else
{
parseModule(module);
}
}*/
if (strchr(searchFunctionName,'#'))
{
//forwarding by ordinal
searchFunctionName++;
ordinal = (WORD)atoi(searchFunctionName);
findApiByModuleAndOrdinal(module, ordinal, &vaApi, &rvaApi);
}
else
{
findApiByModuleAndName(module, searchFunctionName, &vaApi, &rvaApi);
}
if (rvaApi == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"handleForwardedApi :: Api not found, this is really BAD! %S",fordwardedString);
#endif
}
else
{
addApi(functionNameParent,0, ordinalParent, vaApi, rvaApi, true, moduleParent);
}
}
}
ModuleInfo * ApiReader::findModuleByName(WCHAR *name)
{
for (unsigned int i = 0; i < moduleList.size(); i++) {
if (!_wcsicmp(moduleList[i].getFilename(), name))
{
return &moduleList[i];
}
}
return 0;
}
void ApiReader::addApiWithoutName(WORD ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo)
{
addApi(0, 0, ordinal, va, rva, isForwarded, moduleInfo);
}
void ApiReader::addApi(char *functionName, WORD hint, WORD ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo)
{
ApiInfo *apiInfo = new ApiInfo();
if ((functionName != 0) && (strlen(functionName) < _countof(apiInfo->name)))
{
strcpy_s(apiInfo->name, _countof(apiInfo->name), functionName);
}
else
{
apiInfo->name[0] = 0x00;
}
apiInfo->ordinal = ordinal;
apiInfo->isForwarded = isForwarded;
apiInfo->module = moduleInfo;
apiInfo->rva = rva;
apiInfo->va = va;
apiInfo->hint = hint;
setMinMaxApiAddress(va);
moduleInfo->apiList.push_back(apiInfo);
apiList.insert(API_Pair(va, apiInfo));
}
BYTE * ApiReader::getHeaderFromProcess(ModuleInfo * module)
{
BYTE *bufferHeader = 0;
DWORD readSize = 0;
if (module->modBaseSize < PE_HEADER_BYTES_COUNT)
{
readSize = module->modBaseSize;
}
else
{
readSize = PE_HEADER_BYTES_COUNT;
}
bufferHeader = new BYTE[readSize];
if(!readMemoryFromProcess(module->modBaseAddr, readSize, bufferHeader))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getHeaderFromProcess :: Error reading header");
#endif
delete[] bufferHeader;
return 0;
}
else
{
return bufferHeader;
}
}
BYTE * ApiReader::getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader)
{
DWORD readSize = 0;
BYTE *bufferExportTable = 0;
readSize = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
if (readSize < (sizeof(IMAGE_EXPORT_DIRECTORY) + 8))
{
//Something is wrong with the PE Header
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Something is wrong with the PE Header here Export table size %d", readSize);
#endif
readSize = sizeof(IMAGE_EXPORT_DIRECTORY) + 100;
}
if (readSize)
{
bufferExportTable = new BYTE[readSize];
if(!readMemoryFromProcess(module->modBaseAddr + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, readSize, bufferExportTable))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getExportTableFromProcess :: Error reading export table from process");
#endif
delete[] bufferExportTable;
return 0;
}
else
{
return bufferExportTable;
}
}
else
{
return 0;
}
}
void ApiReader::parseModuleWithProcess(ModuleInfo * module)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
BYTE *bufferHeader = 0;
BYTE *bufferExportTable = 0;
bufferHeader = getHeaderFromProcess(module);
if (bufferHeader == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
bufferExportTable = getExportTableFromProcess(module, pNtHeader);
if(bufferExportTable)
{
parseExportTable(module,pNtHeader,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
delete[] bufferExportTable;
}
}
delete[] bufferHeader;
}
void ApiReader::parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress)
{
DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0;
WORD *addressOfNameOrdinalsArray = 0;
char *functionName = 0;
DWORD_PTR RVA = 0, VA = 0;
WORD ordinal = 0;
WORD i = 0, j = 0;
bool withoutName;
addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress);
addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress);
addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseExportTable :: module %s NumberOfNames %X", module->fullPath, pExportDir->NumberOfNames);
#endif
for (i = 0; i < pExportDir->NumberOfNames; i++)
{
functionName = (char*)(addressOfNamesArray[i] + deltaAddress);
ordinal = (WORD)(addressOfNameOrdinalsArray[i] + pExportDir->Base);
RVA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]];
VA = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseExportTable :: api %S ordinal %d imagebase " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" VA " PRINTF_DWORD_PTR_FULL, functionName, ordinal, module->modBaseAddr, RVA, VA);
#endif
if (!isApiBlacklisted(functionName))
{
if (!isApiForwarded(RVA,pNtHeader))
{
addApi(functionName, i, ordinal,VA,RVA,false,module);
}
else
{
//printf("Forwarded: %s\n",functionName);
handleForwardedApi(RVA + deltaAddress,functionName,RVA,ordinal,module);
}
}
}
/*Exports without name*/
if (pExportDir->NumberOfNames != pExportDir->NumberOfFunctions)
{
for (i = 0; i < pExportDir->NumberOfFunctions; i++)
{
withoutName = true;
for (j = 0; j < pExportDir->NumberOfNames; j++)
{
if(addressOfNameOrdinalsArray[j] == i)
{
withoutName = false;
break;
}
}
if (withoutName && addressOfFunctionsArray[i] != 0)
{
ordinal = (WORD)(i+pExportDir->Base);
RVA = addressOfFunctionsArray[i];
VA = (addressOfFunctionsArray[i] + module->modBaseAddr);
if (!isApiForwarded(RVA,pNtHeader))
{
addApiWithoutName(ordinal,VA,RVA,false,module);
}
else
{
handleForwardedApi(RVA + deltaAddress,0,RVA,ordinal,module);
}
}
}
}
}
void ApiReader::findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
findApiByModule(module,0,ordinal,vaApi,rvaApi);
}
void ApiReader::findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
findApiByModule(module,searchFunctionName,0,vaApi,rvaApi);
}
void ApiReader::findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
if (isModuleLoadedInOwnProcess(module))
{
HMODULE hModule = GetModuleHandle(module->getFilename());
if (hModule)
{
if (ordinal)
{
*vaApi = (DWORD_PTR)GetProcAddress(hModule, (LPCSTR)ordinal);
}
else
{
*vaApi = (DWORD_PTR)GetProcAddress(hModule, searchFunctionName);
}
if (vaApi)
{
*rvaApi = (*vaApi) - (DWORD_PTR)hModule;
*vaApi = (*rvaApi) + module->modBaseAddr;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findApiByModule :: vaApi == NULL, should never happen %S", searchFunctionName);
#endif
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findApiByModule :: hModule == NULL, should never happen %s", module->getFilename());
#endif
}
}
else
{
//search api in extern process
findApiInProcess(module,searchFunctionName,ordinal,vaApi,rvaApi);
}
}
bool ApiReader::isModuleLoadedInOwnProcess(ModuleInfo * module)
{
for (unsigned int i = 0; i < ownModuleList.size(); i++)
{
if (!_wcsicmp(module->fullPath, ownModuleList[i].fullPath))
{
//printf("isModuleLoadedInOwnProcess :: %s %s\n",module->fullPath,ownModuleList[i].fullPath);
return true;
}
}
return false;
}
void ApiReader::parseModuleWithOwnProcess( ModuleInfo * module )
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
HMODULE hModule = GetModuleHandle(module->getFilename());
if (hModule)
{
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)hModule + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
parseExportTable(module, pNtHeader, (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)hModule + pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress), (DWORD_PTR)hModule);
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"parseModuleWithOwnProcess :: hModule is NULL");
#endif
}
}
bool ApiReader::isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader)
{
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
Scylla::windowLog.log(L"-> IMAGE_NT_SIGNATURE doesn't match.");
return false;
}
else if ((pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) || (pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0))
{
Scylla::windowLog.log(L"-> No export table.");
return false;
}
else
{
return true;
}
}
void ApiReader::findApiInProcess(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
BYTE *bufferHeader = 0;
BYTE *bufferExportTable = 0;
bufferHeader = getHeaderFromProcess(module);
if (bufferHeader == 0)
return;
pDosHeader = (PIMAGE_DOS_HEADER)bufferHeader;
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)bufferHeader + (DWORD_PTR)(pDosHeader->e_lfanew));
if (isPeAndExportTableValid(pNtHeader))
{
bufferExportTable = getExportTableFromProcess(module, pNtHeader);
if(bufferExportTable)
{
findApiInExportTable(module,(PIMAGE_EXPORT_DIRECTORY)bufferExportTable, (DWORD_PTR)bufferExportTable - pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,searchFunctionName,ordinal,vaApi,rvaApi);
delete[] bufferExportTable;
}
}
delete[] bufferHeader;
}
bool ApiReader::findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi)
{
DWORD *addressOfFunctionsArray = 0,*addressOfNamesArray = 0;
WORD *addressOfNameOrdinalsArray = 0;
char *functionName = 0;
DWORD i = 0, j = 0;
addressOfFunctionsArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfFunctions + deltaAddress);
addressOfNamesArray = (DWORD *)((DWORD_PTR)pExportDir->AddressOfNames + deltaAddress);
addressOfNameOrdinalsArray = (WORD *)((DWORD_PTR)pExportDir->AddressOfNameOrdinals + deltaAddress);
if (searchFunctionName)
{
for (i = 0; i < pExportDir->NumberOfNames; i++)
{
functionName = (char*)(addressOfNamesArray[i] + deltaAddress);
if (!strcmp(functionName,searchFunctionName))
{
*rvaApi = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]];
*vaApi = addressOfFunctionsArray[addressOfNameOrdinalsArray[i]] + module->modBaseAddr;
return true;
}
}
}
else
{
for (i = 0; i < pExportDir->NumberOfFunctions; i++)
{
if (ordinal == (i+pExportDir->Base))
{
*rvaApi = addressOfFunctionsArray[i];
*vaApi = (addressOfFunctionsArray[i] + module->modBaseAddr);
return true;
}
}
}
return false;
}
void ApiReader::setModulePriority(ModuleInfo * module)
{
const WCHAR *moduleFileName = module->getFilename();
//imports by kernelbase don't exist
if (!_wcsicmp(moduleFileName, L"kernelbase.dll"))
{
module->priority = -1;
}
else if (!_wcsicmp(moduleFileName, L"ntdll.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"shlwapi.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"ShimEng.dll"))
{
module->priority = 0;
}
else if (!_wcsicmp(moduleFileName, L"kernel32.dll"))
{
module->priority = 2;
}
else
{
module->priority = 1;
}
}
bool ApiReader::isApiAddressValid(DWORD_PTR virtualAddress)
{
return apiList.count(virtualAddress) > 0;
}
ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect)
{
- stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1, it2;
+ std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1, it2;
size_t c = 0;
size_t countDuplicates = apiList.count(virtualAddress);
int countHighPriority = 0;
ApiInfo *apiFound = 0;
if (countDuplicates == 0)
{
Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress);
return 0;
}
else if (countDuplicates == 1)
{
//API is 100% correct
*isSuspect = false;
it1 = apiList.find(virtualAddress); // Find first match.
return (ApiInfo *)((*it1).second);
}
else
{
it1 = apiList.find(virtualAddress); // Find first match.
//any high priority with a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,true,false,false,false,false);
if (apiFound)
return apiFound;
*isSuspect = true;
//high priority with a name and ansi/unicode name
apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,false);
if (apiFound)
return apiFound;
//priority 2 with no underline in name
apiFound = getScoredApi(it1,countDuplicates,true,false,true,false,false,false,true,false);
if (apiFound)
return apiFound;
//priority 1 with a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,true,false,false);
if (apiFound)
return apiFound;
//With a name
apiFound = getScoredApi(it1,countDuplicates,true,false,false,false,false,false,false,false);
if (apiFound)
return apiFound;
//any with priority, name, ansi/unicode
apiFound = getScoredApi(it1,countDuplicates,true,true,false,true,false,false,false,true);
if (apiFound)
return apiFound;
//any with priority
apiFound = getScoredApi(it1,countDuplicates,false,false,false,true,false,false,false,true);
if (apiFound)
return apiFound;
//has prio 0 and name
apiFound = getScoredApi(it1,countDuplicates,false,false,false,false,true,false,false,true);
if (apiFound)
return apiFound;
}
//is never reached
Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a api resolving bug, VA: " PRINTF_DWORD_PTR_FULL, virtualAddress);
for (size_t c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
Scylla::windowLog.log(L"-> Possible API: %S ord: %d ", apiFound->name, apiFound->ordinal);
}
return (ApiInfo *) 1;
}
/*ApiInfo * ApiReader::getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect)
{
- stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1, it2;
+ std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1, it2;
size_t c = 0;
size_t countDuplicates = apiList.count(virtualAddress);
int countHighPriority = 0;
ApiInfo *apiFound = 0;
if (countDuplicates == 0)
{
Scylla::windowLog.log(L"getApiByVirtualAddress :: No Api found " PRINTF_DWORD_PTR_FULL, virtualAddress);
return 0;
}
else if (countDuplicates == 1)
{
//API is 100% correct
*isSuspect = false;
it1 = apiList.find(virtualAddress); // Find first match.
return (ApiInfo *)((*it1).second);
}
else
{
it1 = apiList.find(virtualAddress); // Find first match.
it2 = it1;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority >= 1) //1 == high priority
{
countHighPriority++;
}
}
it1 = it2;
This is flawed:
It chooses api(prio:1, name:no) over api(prio:0, name:yes)
(e.g. SHLWAPI.PathCombineW vs SHELL32.#25)
Maybe there should be a check higher up in the code, to see if this API is surrounded
by APIs of a DLL and pick the duplicate from that DLL
if (countHighPriority == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == 0 " PRINTF_DWORD_PTR_FULL, virtualAddress);
#endif
*isSuspect = true;
return (ApiInfo *)((*it1).second);
}
else if (countHighPriority == 1) // what about kernel32, it has priority 2
{
//API is 100% correct if countHighPriority == 1 and name export
*isSuspect = false;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority
{
return apiFound;
}
}
}
//else // fall through for case api1(priority:1, name:false) <> api2(priority:0, name:true)
{
//API not 100% correct
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getApiByVirtualAddress :: countHighPriority == %d " PRINTF_DWORD_PTR_FULL, countHighPriority, virtualAddress);
#endif
*isSuspect = true;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
Scylla::windowLog.log(L"%s - %s %X %X\n",apiFound->name, apiFound->module->getFilename(), apiFound->rva, apiFound->ordinal);
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
//prefer APIs with a name
if (apiFound->module->priority >= 1 && apiFound->name[0] != 0x00) //1 == high priority
{
//prefer ANSI/UNICODE APIs
if (strrchr(apiFound->name, 'W') || strrchr(apiFound->name, 'A'))
{
return apiFound;
}
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
//prefer APIs with a name
if (apiFound->module->priority == 2 && !strrchr(apiFound->name, '_')) //1 == high priority
{
return apiFound;
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority == 1 && apiFound->name[0] != 0x00) //1 == high priority
{
return apiFound;
}
}
it1 = it2;
for (c = 0; c < countDuplicates; c++, it1++)
{
apiFound = (ApiInfo *)((*it1).second);
if (apiFound->module->priority == 1) //1 == high priority
{
return apiFound;
}
}
}
}
//is never reached
Scylla::windowLog.log(L"getApiByVirtualAddress :: There is a big bug");
return (ApiInfo *) 1;
}*/
-ApiInfo * ApiReader::getScoredApi(stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin )
+ApiInfo * ApiReader::getScoredApi(std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin )
{
ApiInfo * foundApi = 0;
ApiInfo * foundMatchingApi = 0;
int countFoundApis = 0;
int scoreNeeded = 0;
int scoreValue = 0;
size_t apiNameLength = 0;
if (hasUnicodeAnsiName || hasNoUnderlineInName)
{
hasName = true;
}
if (hasName)
scoreNeeded++;
if (hasUnicodeAnsiName)
scoreNeeded++;
if (hasNoUnderlineInName)
scoreNeeded++;
if (hasPrioDll)
scoreNeeded++;
if (hasPrio0Dll)
scoreNeeded++;
if (hasPrio1Dll)
scoreNeeded++;
if (hasPrio2Dll)
scoreNeeded++;
for (size_t c = 0; c < countDuplicates; c++, it1++)
{
foundApi = (ApiInfo *)((*it1).second);
scoreValue = 0;
if (hasName)
{
if (foundApi->name[0] != 0x00)
{
scoreValue++;
if (hasUnicodeAnsiName)
{
apiNameLength = strlen(foundApi->name);
if ((foundApi->name[apiNameLength - 1] == 'W') || (foundApi->name[apiNameLength - 1] == 'A'))
{
scoreValue++;
}
}
if (hasNoUnderlineInName)
{
if (!strrchr(foundApi->name, '_'))
{
scoreValue++;
}
}
}
}
if (hasPrioDll)
{
if (foundApi->module->priority >= 1)
{
scoreValue++;
}
}
if (hasPrio0Dll)
{
if (foundApi->module->priority == 0)
{
scoreValue++;
}
}
if (hasPrio1Dll)
{
if (foundApi->module->priority == 1)
{
scoreValue++;
}
}
if (hasPrio2Dll)
{
if (foundApi->module->priority == 2)
{
scoreValue++;
}
}
if (scoreValue == scoreNeeded)
{
foundMatchingApi = foundApi;
countFoundApis++;
if (firstWin)
{
return foundMatchingApi;
}
}
}
if (countFoundApis == 1)
{
return foundMatchingApi;
}
else
{
return (ApiInfo *)0;
}
}
void ApiReader::setMinMaxApiAddress(DWORD_PTR virtualAddress)
{
if (virtualAddress < minApiAddress)
{
minApiAddress = virtualAddress - 1;
}
if (virtualAddress > maxApiAddress)
{
maxApiAddress = virtualAddress + 1;
}
}
void ApiReader::readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT, std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew)
{
moduleThunkList = &moduleListNew;
BYTE *dataIat = new BYTE[sizeIAT];
if (readMemoryFromProcess(addressIAT,sizeIAT,dataIat))
{
parseIAT(addressIAT,dataIat,sizeIAT);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ApiReader::readAndParseIAT :: error reading iat " PRINTF_DWORD_PTR_FULL, addressIAT);
#endif
}
delete[] dataIat;
}
void ApiReader::parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size)
{
ApiInfo *apiFound = 0;
ModuleInfo *module = 0;
bool isSuspect = false;
int countApiFound = 0, countApiNotFound = 0;
DWORD_PTR * pIATAddress = (DWORD_PTR *)iatBuffer;
SIZE_T sizeIAT = size / sizeof(DWORD_PTR);
bool foundModuleBreak = false;
for (SIZE_T i = 0; i < sizeIAT; i++)
{
//Scylla::windowLog.log(L"%08X %08X %d von %d", addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i],i,sizeIAT);
if (pIATAddress[i] == 0 || pIATAddress[i] == -1)
{
/*if (pIATAddress[i+1] != 0)
{
printf("parseIAT :: Module break\n");
}*/
/*else
{
printf("parseIAT :: IAT finished\n");
break;
}*/
foundModuleBreak = true;
}
else if ( (pIATAddress[i] > minApiAddress) && (pIATAddress[i] < maxApiAddress) )
{
apiFound = getApiByVirtualAddress(pIATAddress[i], &isSuspect);
if (apiFound == (ApiInfo *)1)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"apiFound == (ApiInfo *)1 -> " PRINTF_DWORD_PTR_FULL, pIATAddress[i]);
#endif
}
else if (apiFound)
{
countApiFound++;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(PRINTF_DWORD_PTR_FULL L" %s %d %s", apiFound->va, apiFound->module->getFilename(), apiFound->ordinal, apiFound->name);
#endif
if (module != apiFound->module)
{
module = apiFound->module;
addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, true, isSuspect);
}
else
{
addFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, apiFound, false, isSuspect);
}
}
else
{
countApiNotFound++;
addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]);
//printf("parseIAT :: API not found %08X\n", pIATAddress[i]);
}
}
else
{
//printf("parseIAT :: API not found %08X\n", pIATAddress[i]);
countApiNotFound++;
addNotFoundApiToModuleList(addressIAT + (DWORD_PTR)&pIATAddress[i] - (DWORD_PTR)iatBuffer, pIATAddress[i]);
}
}
Scylla::windowLog.log(L"IAT parsing finished, found %d valid APIs, missed %d APIs", countApiFound, countApiNotFound);
}
void ApiReader::addFoundApiToModuleList(DWORD_PTR iatAddressVA, ApiInfo * apiFound, bool isNewModule, bool isSuspect)
{
if (isNewModule)
{
addModuleToModuleList(apiFound->module->getFilename(), iatAddressVA - targetImageBase);
}
addFunctionToModuleList(apiFound, iatAddressVA, iatAddressVA - targetImageBase, apiFound->ordinal, true, isSuspect);
}
bool ApiReader::addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk)
{
ImportModuleThunk module;
module.firstThunk = firstThunk;
wcscpy_s(module.moduleName, _countof(module.moduleName), moduleName);
(*moduleThunkList).insert(std::pair<DWORD_PTR,ImportModuleThunk>(firstThunk,module));
return true;
}
void ApiReader::addUnknownModuleToModuleList(DWORD_PTR firstThunk)
{
ImportModuleThunk module;
module.firstThunk = firstThunk;
wcscpy_s(module.moduleName, _countof(module.moduleName), L"?");
(*moduleThunkList).insert(std::pair<DWORD_PTR,ImportModuleThunk>(firstThunk,module));
}
bool ApiReader::addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect)
{
ImportThunk import;
ImportModuleThunk * module = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iterator1;
if ((*moduleThunkList).size() > 1)
{
iterator1 = (*moduleThunkList).begin();
while (iterator1 != (*moduleThunkList).end())
{
if (rva >= iterator1->second.firstThunk)
{
iterator1++;
if (iterator1 == (*moduleThunkList).end())
{
iterator1--;
module = &(iterator1->second);
break;
}
else if (rva < iterator1->second.firstThunk)
{
iterator1--;
module = &(iterator1->second);
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Error iterator1 != (*moduleThunkList).end()");
#endif
break;
}
}
}
else
{
iterator1 = (*moduleThunkList).begin();
module = &(iterator1->second);
}
if (!module)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL, rva);
#endif
return false;
}
import.suspect = suspect;
import.valid = valid;
import.va = va;
import.rva = rva;
import.apiAddressVA = apiFound->va;
import.ordinal = ordinal;
import.hint = (WORD)apiFound->hint;
wcscpy_s(import.moduleName, _countof(import.moduleName), apiFound->module->getFilename());
strcpy_s(import.name, _countof(import.name), apiFound->name);
module->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(import.rva, import));
return true;
}
void ApiReader::clearAll()
{
minApiAddress = -1;
maxApiAddress = 0;
- for ( stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it = apiList.begin(); it != apiList.end(); ++it )
+ for ( std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it = apiList.begin(); it != apiList.end(); ++it )
{
delete it->second;
}
apiList.clear();
if (moduleThunkList != 0)
{
(*moduleThunkList).clear();
}
}
bool ApiReader::addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress)
{
ImportThunk import;
ImportModuleThunk * module = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iterator1;
DWORD_PTR rva = iatAddressVA - targetImageBase;
if ((*moduleThunkList).size() > 0)
{
iterator1 = (*moduleThunkList).begin();
while (iterator1 != (*moduleThunkList).end())
{
if (rva >= iterator1->second.firstThunk)
{
iterator1++;
if (iterator1 == (*moduleThunkList).end())
{
iterator1--;
//new unknown module
if (iterator1->second.moduleName[0] == L'?')
{
module = &(iterator1->second);
}
else
{
addUnknownModuleToModuleList(rva);
module = &((*moduleThunkList).find(rva)->second);
}
break;
}
else if (rva < iterator1->second.firstThunk)
{
iterator1--;
module = &(iterator1->second);
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Error iterator1 != (*moduleThunkList).end()\r\n");
#endif
break;
}
}
}
else
{
//new unknown module
addUnknownModuleToModuleList(rva);
module = &((*moduleThunkList).find(rva)->second);
}
if (!module)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ImportsHandling::addFunction module not found rva " PRINTF_DWORD_PTR_FULL,rva);
#endif
return false;
}
import.suspect = true;
import.valid = false;
import.va = iatAddressVA;
import.rva = rva;
import.apiAddressVA = apiAddress;
import.ordinal = 0;
wcscpy_s(import.moduleName, _countof(import.moduleName), L"?");
strcpy_s(import.name, _countof(import.name), "?");
module->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(import.rva, import));
return true;
}
bool ApiReader::isApiBlacklisted( const char * functionName )
{
if (SystemInformation::currenOS < WIN_VISTA_32)
{
if (!strcmp(functionName, "RestoreLastError"))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
/*#ifdef _WIN64
else if (SystemInformation::currenOS == WIN_XP_64 && !strcmp(functionName, "DecodePointer"))
{
return true;
}
#endif*/
}
bool ApiReader::isWinSxSModule( ModuleInfo * module )
{
if (wcsstr(module->fullPath, L"\\WinSxS\\"))
{
return true;
}
else if (wcsstr(module->fullPath, L"\\winsxs\\"))
{
return true;
}
else
{
return false;
}
}
diff --git a/Scylla/ApiReader.h b/Scylla/ApiReader.h
index ebcc6f2..81e4bea 100644
--- a/Scylla/ApiReader.h
+++ b/Scylla/ApiReader.h
@@ -1,72 +1,74 @@
#pragma once
+#include <windows.h>
+#include <map>
+#include <unordered_map>
#include "ProcessAccessHelp.h"
#include "Thunks.h"
typedef std::pair<DWORD_PTR, ApiInfo *> API_Pair;
-class ApiReader : public ProcessAccessHelp {
+class ApiReader : public ProcessAccessHelp
+{
public:
- static stdext::hash_multimap<DWORD_PTR, ApiInfo *> apiList; //api look up table
+ static std::unordered_map<DWORD_PTR, ApiInfo *> apiList; //api look up table
static std::map<DWORD_PTR, ImportModuleThunk> * moduleThunkList; //store found apis
static DWORD_PTR minApiAddress;
static DWORD_PTR maxApiAddress;
/*
* Read all APIs from target process
*/
void readApisFromModuleList();
-
bool isApiAddressValid(DWORD_PTR virtualAddress);
ApiInfo * getApiByVirtualAddress(DWORD_PTR virtualAddress, bool * isSuspect);
- void readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT,std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew );
+ void readAndParseIAT(DWORD_PTR addressIAT, DWORD sizeIAT, std::map<DWORD_PTR, ImportModuleThunk> &moduleListNew );
void clearAll();
private:
+
void parseIAT(DWORD_PTR addressIAT, BYTE * iatBuffer, SIZE_T size);
void addApi(char *functionName, WORD hint, WORD ordinal, DWORD_PTR va, DWORD_PTR rva, bool isForwarded, ModuleInfo *moduleInfo);
void addApiWithoutName(WORD ordinal, DWORD_PTR va, DWORD_PTR rva,bool isForwarded, ModuleInfo *moduleInfo);
inline bool isApiForwarded(DWORD_PTR rva, PIMAGE_NT_HEADERS pNtHeader);
void handleForwardedApi(DWORD_PTR vaStringPointer,char *functionNameParent,DWORD_PTR rvaParent, WORD ordinalParent, ModuleInfo *moduleParent);
void parseModule(ModuleInfo *module);
void parseModuleWithProcess(ModuleInfo * module);
-
void parseExportTable(ModuleInfo *module, PIMAGE_NT_HEADERS pNtHeader, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress);
ModuleInfo * findModuleByName(WCHAR *name);
void findApiByModuleAndOrdinal(ModuleInfo * module, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
void findApiByModuleAndName(ModuleInfo * module, char * searchFunctionName, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
void findApiByModule(ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
bool isModuleLoadedInOwnProcess( ModuleInfo * module );
void parseModuleWithOwnProcess( ModuleInfo * module );
bool isPeAndExportTableValid(PIMAGE_NT_HEADERS pNtHeader);
void findApiInProcess( ModuleInfo * module, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi );
bool findApiInExportTable(ModuleInfo *module, PIMAGE_EXPORT_DIRECTORY pExportDir, DWORD_PTR deltaAddress, char * searchFunctionName, WORD ordinal, DWORD_PTR * vaApi, DWORD_PTR * rvaApi);
BYTE * getHeaderFromProcess(ModuleInfo * module);
BYTE * getExportTableFromProcess(ModuleInfo * module, PIMAGE_NT_HEADERS pNtHeader);
void setModulePriority(ModuleInfo * module);
void setMinMaxApiAddress(DWORD_PTR virtualAddress);
-
void parseModuleWithMapping(ModuleInfo *moduleInfo); //not used
void addFoundApiToModuleList(DWORD_PTR iatAddress, ApiInfo * apiFound, bool isNewModule, bool isSuspect);
bool addModuleToModuleList(const WCHAR * moduleName, DWORD_PTR firstThunk);
bool addFunctionToModuleList(ApiInfo * apiFound, DWORD_PTR va, DWORD_PTR rva, WORD ordinal, bool valid, bool suspect);
bool addNotFoundApiToModuleList(DWORD_PTR iatAddressVA, DWORD_PTR apiAddress);
void addUnknownModuleToModuleList(DWORD_PTR firstThunk);
bool isApiBlacklisted( const char * functionName );
bool isWinSxSModule( ModuleInfo * module );
- ApiInfo * getScoredApi(stdext::hash_multimap<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin );
-};
\ No newline at end of file
+ ApiInfo * getScoredApi(std::unordered_map<DWORD_PTR, ApiInfo *>::iterator it1,size_t countDuplicates, bool hasName, bool hasUnicodeAnsiName, bool hasNoUnderlineInName, bool hasPrioDll,bool hasPrio0Dll,bool hasPrio1Dll, bool hasPrio2Dll, bool firstWin );
+};
diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp
index 52ab836..c04838f 100644
--- a/Scylla/ConfigurationHolder.cpp
+++ b/Scylla/ConfigurationHolder.cpp
@@ -1,205 +1,202 @@
#include "ConfigurationHolder.h"
#include <shlwapi.h>
-#include <stdio.h>
#include "Architecture.h"
const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG";
//#define DEBUG_COMMENTS
ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName)
{
config[USE_PE_HEADER_FROM_DISK] = Configuration(L"USE_PE_HEADER_FROM_DISK", Configuration::Boolean);
config[DEBUG_PRIVILEGE] = Configuration(L"DEBUG_PRIVILEGE", Configuration::Boolean);
config[CREATE_BACKUP] = Configuration(L"CREATE_BACKUP", Configuration::Boolean);
config[DLL_INJECTION_AUTO_UNLOAD] = Configuration(L"DLL_INJECTION_AUTO_UNLOAD", Configuration::Boolean);
config[UPDATE_HEADER_CHECKSUM] = Configuration(L"UPDATE_HEADER_CHECKSUM", Configuration::Boolean);
config[IAT_SECTION_NAME] = Configuration(L"IAT_SECTION_NAME", Configuration::String);
buildConfigFilePath(fileName);
}
bool ConfigurationHolder::loadConfiguration()
{
std::map<ConfigOption, Configuration>::iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
Configuration& configObject = mapIter->second;
if (!loadConfig(configObject))
{
return false;
}
}
return true;
}
bool ConfigurationHolder::saveConfiguration() const
{
std::map<ConfigOption, Configuration>::const_iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
const Configuration& configObject = mapIter->second;
if (!saveConfig(configObject))
{
return false;
}
}
return true;
}
Configuration& ConfigurationHolder::operator[](ConfigOption option)
{
return config[option];
}
const Configuration& ConfigurationHolder::operator[](ConfigOption option) const
{
static const Configuration dummy;
std::map<ConfigOption, Configuration>::const_iterator found = config.find(option);
if(found != config.end())
{
return found->second;
}
else
{
return dummy;
}
}
bool ConfigurationHolder::saveNumericToConfigFile(const Configuration & configObject, int nBase) const
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
if (nBase == 16)
{
swprintf_s(buf, PRINTF_DWORD_PTR_FULL, configObject.getNumeric());
}
else
{
swprintf_s(buf, PRINTF_INTEGER, configObject.getNumeric());
}
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), buf, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase)
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if (read > 0 && wcslen(buf) > 0)
{
#ifdef _WIN64
configObject.setNumeric(_wcstoui64(buf, NULL, nBase));
#else
configObject.setNumeric(wcstoul(buf, NULL, nBase));
#endif
return true;
}
return false;
}
bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const
{
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject)
{
WCHAR buf[Configuration::CONFIG_STRING_LENGTH];
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if(read > 0 && wcslen(buf) > 0)
{
configObject.setString(buf);
return true;
}
return false;
}
bool ConfigurationHolder::readBooleanFromConfigFile(Configuration & configObject)
{
UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath);
configObject.setBool(val != 0);
return true;
}
bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const
{
const WCHAR *boolValue = configObject.isTrue() ? L"1" : L"0";
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), boolValue, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::loadConfig(Configuration & configObject)
{
switch (configObject.getType())
{
case Configuration::String:
return readStringFromConfigFile(configObject);
case Configuration::Boolean:
return readBooleanFromConfigFile(configObject);
case Configuration::Decimal:
return readNumericFromConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return readNumericFromConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::saveConfig(const Configuration & configObject) const
{
switch (configObject.getType())
{
case Configuration::String:
return saveStringToConfigFile(configObject);
case Configuration::Boolean:
return saveBooleanToConfigFile(configObject);
case Configuration::Decimal:
return saveNumericToConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return saveNumericToConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::buildConfigFilePath(const WCHAR* fileName)
{
ZeroMemory(configPath, sizeof(configPath));
if (!GetModuleFileName(0, configPath, _countof(configPath)))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"buildConfigFilePath :: GetModuleFileName failed %d", GetLastError());
#endif
return false;
}
PathRemoveFileSpec(configPath);
PathAppend(configPath, fileName);
- //wprintf(L"configPath %s\n\n", configPath);
-
return true;
}
diff --git a/Scylla/DllInjection.cpp b/Scylla/DllInjection.cpp
index d309309..c8f5fed 100644
--- a/Scylla/DllInjection.cpp
+++ b/Scylla/DllInjection.cpp
@@ -1,246 +1,246 @@
#include "DllInjection.h"
-#include "Logger.h"
#include <Psapi.h>
+#include "Scylla.h"
#include "NativeWinApi.h"
//#define DEBUG_COMMENTS
HMODULE DllInjection::dllInjection(HANDLE hProcess, const WCHAR * filename)
{
LPVOID remoteMemory = 0;
SIZE_T memorySize = 0;
HANDLE hThread = 0;
HMODULE hModule = 0;
memorySize = (wcslen(filename) + 1) * sizeof(WCHAR);
if (memorySize < 7)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: memorySize invalid");
#endif
return 0;
}
remoteMemory = VirtualAllocEx(hProcess, NULL, memorySize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (remoteMemory == 0)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: VirtualAllocEx failed 0x%X", GetLastError());
#endif
return 0;
}
if (WriteProcessMemory(hProcess, remoteMemory, filename, memorySize, &memorySize))
{
hThread = startRemoteThread(hProcess,LoadLibraryW,remoteMemory);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
#ifdef _WIN64
hModule = getModuleHandleByFilename(hProcess, filename);
#else
//returns only 32 bit values -> design bug by microsoft
if (!GetExitCodeThread(hThread, (LPDWORD) &hModule))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: GetExitCodeThread failed 0x%X", GetLastError());
#endif
hModule = 0;
}
#endif
CloseHandle(hThread);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: CreateRemoteThread failed 0x%X", GetLastError());
#endif
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dllInjection :: WriteProcessMemory failed 0x%X", GetLastError());
#endif
}
VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
return hModule;
}
bool DllInjection::unloadDllInProcess(HANDLE hProcess, HMODULE hModule)
{
HANDLE hThread = 0;
DWORD lpThreadId = 0;
BOOL freeLibraryRet = 0;
hThread = startRemoteThread(hProcess,FreeLibrary,hModule);
if (hThread)
{
WaitForSingleObject(hThread, INFINITE);
if (!GetExitCodeThread(hThread, (LPDWORD) &freeLibraryRet))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"unloadDllInProcess :: GetExitCodeThread failed 0x%X", GetLastError());
#endif
freeLibraryRet = 0;
}
CloseHandle(hThread);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"unloadDllInProcess :: CreateRemoteThread failed 0x%X", GetLastError());
#endif
}
return freeLibraryRet != 0;
}
HMODULE DllInjection::getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename )
{
HMODULE * hMods = 0;
HMODULE hModResult = 0;
DWORD count = 0;
WCHAR target[MAX_PATH];
DWORD cbNeeded = 0;
bool notEnough = true;
count = 100;
hMods = new HMODULE[count];
do
{
if (!EnumProcessModules(hProcess, hMods, count * sizeof(HMODULE), &cbNeeded))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: EnumProcessModules failed count %d", count);
#endif
delete [] hMods;
return 0;
}
if ( (count * sizeof(HMODULE)) < cbNeeded )
{
delete [] hMods;
count += 100;
hMods = new HMODULE[count];
}
else
{
notEnough = false;
}
} while (notEnough);
for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
if (GetModuleFileNameExW(hProcess, hMods[i], target, _countof(target)))
{
if (!_wcsicmp(target,filename))
{
hModResult = hMods[i];
break;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError());
#endif
}
}
if (!hModResult)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"DllInjection::getModuleHandle :: Handle not found");
#endif
}
delete [] hMods;
return hModResult;
}
void DllInjection::specialThreadSettings( HANDLE hThread )
{
if (hThread)
{
if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"specialThreadSettings :: SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) failed 0x%X", GetLastError());
#endif
}
if (NativeWinApi::NtSetInformationThread)
{
if (NativeWinApi::NtSetInformationThread(hThread, ThreadHideFromDebugger, 0, 0) != STATUS_SUCCESS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"specialThreadSettings :: NtSetInformationThread ThreadHideFromDebugger failed");
#endif
}
}
}
}
HANDLE DllInjection::startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
{
HANDLE hThread = 0;
hThread = customCreateRemoteThread(hProcess, lpStartAddress, lpParameter);
if (hThread)
{
specialThreadSettings(hThread);
ResumeThread(hThread);
}
return hThread;
}
HANDLE DllInjection::customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
{
DWORD lpThreadId = 0;
HANDLE hThread = 0;
NTSTATUS ntStatus = 0;
if (NativeWinApi::NtCreateThreadEx)
{
#define THREAD_ALL_ACCESS_VISTA_7 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
//for windows vista/7
ntStatus = NativeWinApi::NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS_VISTA_7, 0, hProcess, (LPTHREAD_START_ROUTINE)lpStartAddress, (LPVOID)lpParameter, TRUE, 0, 0, 0, 0);
if (NT_SUCCESS(ntStatus))
{
return hThread;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"customCreateRemoteThread :: NtCreateThreadEx failed 0x%X", NativeWinApi::RtlNtStatusToDosError(ntStatus));
#endif
return 0;
}
}
else
{
return CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)lpStartAddress,lpParameter,CREATE_SUSPENDED,&lpThreadId);
}
}
diff --git a/Scylla/DllInjection.h b/Scylla/DllInjection.h
index ddd0a6d..a7af9e6 100644
--- a/Scylla/DllInjection.h
+++ b/Scylla/DllInjection.h
@@ -1,17 +1,18 @@
-#include <windows.h>
-#include <Commctrl.h>
-#include <stdio.h>
-#include <map>
+#pragma once
+#include <windows.h>
-class DllInjection {
+class DllInjection
+{
public:
+
HMODULE dllInjection(HANDLE hProcess, const WCHAR * filename);
bool unloadDllInProcess(HANDLE hProcess, HMODULE hModule);
HANDLE startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter);
private:
+
HANDLE customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter);
- void specialThreadSettings( HANDLE hThread );
- HMODULE getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename );
-};
\ No newline at end of file
+ void specialThreadSettings(HANDLE hThread);
+ HMODULE getModuleHandleByFilename(HANDLE hProcess, const WCHAR * filename);
+};
diff --git a/Scylla/DllInjectionPlugin.h b/Scylla/DllInjectionPlugin.h
index 1f22613..131970c 100644
--- a/Scylla/DllInjectionPlugin.h
+++ b/Scylla/DllInjectionPlugin.h
@@ -1,65 +1,66 @@
+#pragma once
+
#include "DllInjection.h"
#include "PluginLoader.h"
#include "Thunks.h"
#include "ApiReader.h"
-
#define PLUGIN_IMPREC_EXCHANGE_DLL_PATH "ScyllaImprecPluginExchangePath"
#define SCYLLA_STATUS_SUCCESS 0
#define SCYLLA_STATUS_UNKNOWN_ERROR 1
#define SCYLLA_STATUS_UNSUPPORTED_PROTECTION 2
#define SCYLLA_STATUS_IMPORT_RESOLVING_FAILED 3
#define SCYLLA_STATUS_MAPPING_FAILED 0xFF
/* Important note:
*
* If you write a plugin for the x86 (32-Bit) edition: DWORD_PTR address has 32 bit (4 byte)
* If you write a plugin for the x64 (64-Bit) edition: DWORD_PTR address has 64 bit (8 byte)
*/
typedef struct _UNRESOLVED_IMPORT { // Scylla Plugin exchange format
DWORD_PTR ImportTableAddressPointer; //in VA, address in IAT which points to an invalid api address
DWORD_PTR InvalidApiAddress; //in VA, invalid api address that needs to be resolved
} UNRESOLVED_IMPORT, *PUNRESOLVED_IMPORT;
typedef struct _SCYLLA_EXCHANGE {
BYTE status; //return a status, default 0xFF
DWORD_PTR imageBase; //image base
DWORD_PTR imageSize; //size of the image
DWORD_PTR numberOfUnresolvedImports; //number of unresolved imports in this structure
BYTE offsetUnresolvedImportsArray;
} SCYLLA_EXCHANGE, *PSCYLLA_EXCHANGE;
class DllInjectionPlugin : public DllInjection {
public:
static const WCHAR * FILE_MAPPING_NAME;
static HANDLE hProcess;
ApiReader * apiReader;
HANDLE hMapFile;
LPVOID lpViewOfFile;
DllInjectionPlugin()
{
hMapFile = 0;
lpViewOfFile = 0;
apiReader = 0;
}
~DllInjectionPlugin()
{
closeAllHandles();
}
void injectPlugin(Plugin & plugin, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize);
void injectImprecPlugin(Plugin & plugin, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR imageBase, DWORD_PTR imageSize);
private:
bool createFileMapping(DWORD mappingSize);
void closeAllHandles();
DWORD_PTR getNumberOfUnresolvedImports( std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void addUnresolvedImports( PUNRESOLVED_IMPORT firstUnresImp, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void handlePluginResults( PSCYLLA_EXCHANGE scyllaExchange, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void updateImportsWithPluginResult( PUNRESOLVED_IMPORT firstUnresImp, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
-};
\ No newline at end of file
+};
diff --git a/Scylla/IATSearch.h b/Scylla/IATSearch.h
index 781eaba..633527e 100644
--- a/Scylla/IATSearch.h
+++ b/Scylla/IATSearch.h
@@ -1,29 +1,29 @@
#pragma once
#include "ApiReader.h"
-
-class IATSearch : protected ApiReader {
+class IATSearch : protected ApiReader
+{
public:
DWORD_PTR memoryAddress;
SIZE_T memorySize;
bool searchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT);
private:
DWORD_PTR findAPIAddressInIAT(DWORD_PTR startAddress);
DWORD_PTR findNextFunctionAddress();
DWORD_PTR findIATPointer();
//DWORD_PTR findAddressFromWORDString(char * stringBuffer);
//DWORD_PTR findAddressFromNormalCALLString(char * stringBuffer);
bool isIATPointerValid(DWORD_PTR iatPointer);
bool findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT);
DWORD_PTR findIATStartAddress( DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer );
DWORD findIATSize( DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize );
bool isAddressAccessable(DWORD_PTR address);
-};
\ No newline at end of file
+};
diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp
index 38c56ff..03111e6 100644
--- a/Scylla/ImportRebuild.cpp
+++ b/Scylla/ImportRebuild.cpp
@@ -1,715 +1,713 @@
#include "ImportRebuild.h"
#include "Scylla.h"
-//#include "ConfigurationHolder.h"
+#include "StringConversion.h"
//#define DEBUG_COMMENTS
ImportRebuild::ImportRebuild()
{
imageData = NULL;
sizeOfFile = 0;
pDosStub = NULL;
pOverlay = NULL;
sizeOfOverlay = 0;
pImportDescriptor = NULL;
pThunkData = NULL;
pImportByName = NULL;
numberOfImportDescriptors = 0;
sizeOfImportSection = 0;
sizeOfApiAndModuleNames = 0;
importSectionIndex = 0;
}
ImportRebuild::~ImportRebuild()
{
delete [] pDosStub;
delete [] imageData;
for (size_t i = 0; i < vecSectionData.size(); i++)
{
delete [] vecSectionData[i];
}
delete [] pOverlay;
}
bool ImportRebuild::splitTargetFile()
{
PIMAGE_SECTION_HEADER pSecHeader = 0;
BYTE * data = 0;
DWORD alignment = 0;
DosHeader = *(IMAGE_DOS_HEADER*)imageData;
if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
{
return false;
}
NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew);
if (NTHeader.Signature != IMAGE_NT_SIGNATURE)
{
return false;
}
if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER))
{
size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
pDosStub = new BYTE[sizeOfStub];
CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub);
}
pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew));
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
const DWORD SECTION_SIZE_MAX = 300000000;
DWORD sizeOfSection = pSecHeader->SizeOfRawData;
if (sizeOfSection > SECTION_SIZE_MAX)
{
sizeOfSection = SECTION_SIZE_MAX;
}
//TODO better use section alignment because it is better?
alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment);
data = new BYTE[alignment];
ZeroMemory(data, alignment);
CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection);
vecSectionData.push_back(data);
vecSectionHeaders.push_back(*pSecHeader);
pSecHeader++;
}
if(NTHeader.FileHeader.NumberOfSections > 0) // ??
{
const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin());
DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData;
if (calcSize < sizeOfFile)
{
sizeOfOverlay = sizeOfFile - calcSize;
pOverlay = new BYTE[sizeOfOverlay];
memcpy(pOverlay, imageData + calcSize, sizeOfOverlay);
}
}
delete [] imageData;
imageData = 0;
return true;
}
bool ImportRebuild::alignSectionHeaders()
{
for (WORD i = 0; i < vecSectionHeaders.size(); i++)
{
vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment);
vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment);
vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment);
vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment);
}
return true;
}
bool ImportRebuild::saveNewFile(const WCHAR * filepath)
{
DWORD fileOffset = 0;
DWORD dwWriteSize = 0;
size_t i = 0;
if (vecSectionHeaders.size() != vecSectionData.size())
{
return false;
}
HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(hFile == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return false;
}
//alignSectionHeaders();
updatePeHeader();
fileOffset = 0;
dwWriteSize = sizeof(IMAGE_DOS_HEADER);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader);
fileOffset += dwWriteSize;
dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub);
fileOffset += dwWriteSize;
dwWriteSize = sizeof(IMAGE_NT_HEADERS);
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader);
fileOffset += dwWriteSize;
dwWriteSize = sizeof(IMAGE_SECTION_HEADER);
for (i = 0; i < vecSectionHeaders.size(); i++)
{
if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i]))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
#endif
CloseHandle(hFile);
return false;
}
fileOffset += dwWriteSize;
}
for (i = 0; i < vecSectionHeaders.size(); i++)
{
dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset;
if (dwWriteSize)
{
if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
#endif
CloseHandle(hFile);
return false;
}
fileOffset += dwWriteSize;
}
dwWriteSize = vecSectionHeaders[i].SizeOfRawData;
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]);
fileOffset += dwWriteSize;
}
if(pOverlay)
{
ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, sizeOfOverlay, pOverlay);
fileOffset += sizeOfOverlay;
}
CloseHandle(hFile);
return true;
}
bool ImportRebuild::writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size)
{
bool retValue = false;
PVOID zeromemory = calloc(size, 1);
if (zeromemory)
{
retValue = ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, size, zeromemory);
free(zeromemory);
}
else
{
retValue = false;
}
return retValue;
}
bool ImportRebuild::addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData)
{
BYTE * newBuffer = 0;
IMAGE_SECTION_HEADER pNewSection = {0};
size_t lastSectionIndex = vecSectionHeaders.size() - 1;
size_t nameLength = strlen(sectionName);
if (nameLength > IMAGE_SIZEOF_SHORT_NAME)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addNewSection :: sectionname is too long %d", nameLength);
#endif
return false;
}
memcpy_s(pNewSection.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength);
pNewSection.SizeOfRawData = alignValue(sectionSize, NTHeader.OptionalHeader.FileAlignment);
pNewSection.Misc.VirtualSize = alignValue(sectionSize, NTHeader.OptionalHeader.SectionAlignment);
pNewSection.PointerToRawData = alignValue(vecSectionHeaders[lastSectionIndex].PointerToRawData + vecSectionHeaders[lastSectionIndex].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment);
pNewSection.VirtualAddress = alignValue(vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment);
pNewSection.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA;
vecSectionHeaders.push_back(pNewSection);
if ( (sectionSize != pNewSection.SizeOfRawData) || (sectionData == 0) )
{
newBuffer = new BYTE[pNewSection.SizeOfRawData];
ZeroMemory(newBuffer, pNewSection.SizeOfRawData);
if (sectionData)
{
CopyMemory(newBuffer, sectionData, sectionSize);
}
}
else
{
newBuffer = sectionData;
}
vecSectionData.push_back(newBuffer);
return true;
}
bool ImportRebuild::loadTargetFile(const WCHAR * filepath)
{
HANDLE hTargetFile = INVALID_HANDLE_VALUE;
DWORD fileSize = 0;
bool retValue = false;
hTargetFile = CreateFile(filepath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(hTargetFile == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"loadTargetFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return false;
}
fileSize = (DWORD)ProcessAccessHelp::getFileSize(hTargetFile);
if (!fileSize)
{
CloseHandle(hTargetFile);
hTargetFile = 0;
return false;
}
imageData = new BYTE[fileSize];
if (!imageData)
{
retValue = false;
}
else
{
sizeOfFile = fileSize;
retValue = ProcessAccessHelp::readMemoryFromFile(hTargetFile, 0, fileSize, imageData);
}
CloseHandle(hTargetFile);
hTargetFile = 0;
return retValue;
}
DWORD ImportRebuild::alignValue(DWORD badValue, DWORD alignTo)
{
return (((badValue + alignTo - 1) / alignTo) * alignTo);
}
DWORD ImportRebuild::convertRVAToOffsetVector(DWORD dwRVA)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= dwRVA) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > dwRVA))
{
return ((dwRVA - vecSectionHeaders[i].VirtualAddress) + vecSectionHeaders[i].PointerToRawData);
}
}
return 0;
}
/*
DWORD ImportRebuild::convertRVAToOffset(DWORD dwRVA)
{
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader);
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
if ((pSectionHeader->VirtualAddress <= dwRVA) && ((pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize) > dwRVA))
{
return ((dwRVA - pSectionHeader->VirtualAddress) + pSectionHeader->PointerToRawData);
}
pSectionHeader++;
}
return 0;
}
*/
DWORD_PTR ImportRebuild::convertOffsetToRVAVector(DWORD dwOffset)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].PointerToRawData <= dwOffset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > dwOffset))
{
return ((dwOffset - vecSectionHeaders[i].PointerToRawData) + vecSectionHeaders[i].VirtualAddress);
}
}
return 0;
}
/*
DWORD ImportRebuild::convertOffsetToRVA(DWORD dwOffset)
{
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(&NTHeader);
for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
{
if ((pSectionHeader->PointerToRawData <= dwOffset) && ((pSectionHeader->PointerToRawData + pSectionHeader->SizeOfRawData) > dwOffset))
{
return ((dwOffset - pSectionHeader->PointerToRawData) + pSectionHeader->VirtualAddress);
}
pSectionHeader++;
}
return 0;
}
*/
void ImportRebuild::updatePeHeader()
{
size_t lastSectionIndex = vecSectionHeaders.size() - 1;
NTHeader.FileHeader.NumberOfSections = (WORD)(lastSectionIndex + 1);
NTHeader.OptionalHeader.SizeOfImage = vecSectionHeaders[lastSectionIndex].VirtualAddress + vecSectionHeaders[lastSectionIndex].Misc.VirtualSize;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
if (NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress))
{
//section must be read and writeable
vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
}
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
NTHeader.OptionalHeader.NumberOfRvaAndSizes = 0x10;
NTHeader.OptionalHeader.SizeOfHeaders = alignValue(DosHeader.e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + NTHeader.FileHeader.SizeOfOptionalHeader + (NTHeader.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)), NTHeader.OptionalHeader.FileAlignment);
}
bool ImportRebuild::buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
createNewImportSection(moduleList);
importSectionIndex = vecSectionHeaders.size() - 1;
DWORD dwSize = fillImportSection(moduleList);
if (!dwSize)
{
return false;
}
setFlagToIATSection((*moduleList.begin()).second.firstThunk);
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = vecSectionHeaders[importSectionIndex].VirtualAddress;
NTHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
return true;
}
bool ImportRebuild::createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
char sectionName[9] = {0};
- size_t i = 0;
//DWORD sectionSize = calculateMinSize(moduleList);
calculateImportSizes(moduleList);
if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME)
{
strcpy_s(sectionName, sizeof(sectionName), ".SCY");
}
else
{
- wcstombs_s(&i, sectionName, sizeof(sectionName), Scylla::config[IAT_SECTION_NAME].getString(), _TRUNCATE);
+ StringConversion::ToASCII(Scylla::config[IAT_SECTION_NAME].getString(), sectionName, _countof(sectionName));
}
-
return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0);
}
/*DWORD ImportRebuild::calculateMinSize(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
DWORD dwSize = 0;
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
//dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME));
dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
if((*mapIt2).second.name[0] != '\0')
{
dwSize += sizeof(IMAGE_IMPORT_BY_NAME);
dwSize += (DWORD)strlen((*mapIt2).second.name);
}
}
}
return dwSize;
}*/
BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA)
{
DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA);
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset))
{
return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData));
}
}
return 0;
}
DWORD ImportRebuild::fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;
PIMAGE_IMPORT_BY_NAME pImportByName = 0;
PIMAGE_THUNK_DATA pThunk = 0;
ImportModuleThunk * importModuleThunk = 0;
ImportThunk * importThunk = 0;
size_t stringLength = 0;
DWORD_PTR lastRVA = 0;
BYTE * sectionData = vecSectionData[importSectionIndex];
DWORD offset = 0;
pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData);
//skip the IMAGE_IMPORT_DESCRIPTOR
offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
importModuleThunk = &((*mapIt).second);
stringLength = addImportDescriptor(importModuleThunk, offset);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name);
#endif
offset += (DWORD)stringLength; //stringLength has null termination char
pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset);
//pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk));
lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
importThunk = &((*mapIt2).second);
pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva));
//check wrong iat pointer
if (!pThunk)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva);
#endif
return 0;
}
if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva)
{
//add additional import desc
addSpecialImportDescriptor(importThunk->rva);
}
lastRVA = importThunk->rva;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset);
#endif
stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset);
offset += (DWORD)stringLength; //is 0 bei import by ordinal
pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength);
}
pImportDescriptor++;
}
return offset;
}
bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
bool retValue = false;
if (loadTargetFile(targetFilePath))
{
splitTargetFile();
retValue = buildNewImportTable(moduleList);
if (retValue)
{
retValue = saveNewFile(newFilePath);
}
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath);
#endif
return false;
}
}
void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress)
{
for (size_t i = 0; i < vecSectionHeaders.size(); i++)
{
if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress))
{
//section must be read and writeable
vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
}
}
size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset)
{
size_t stringLength = 0;
if(pImport->name[0] == '\0')
{
pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG);
}
else
{
pImportByName->Hint = pImport->hint;
stringLength = strlen(pImport->name) + 1;
memcpy(pImportByName->Name, pImport->name, stringLength);
pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
if (!pThunk->u1.AddressOfData)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset);
#endif
}
//next import should be nulled
pThunk++;
pThunk->u1.AddressOfData = 0;
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
#endif
stringLength += sizeof(WORD);
}
return stringLength;
}
size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset)
{
char dllName[MAX_PATH];
- size_t stringLength = 0;
- wcstombs_s(&stringLength, dllName, (size_t)_countof(dllName), pImportModule->moduleName, (size_t)_countof(pImportModule->moduleName));
+ StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName));
+ size_t stringLength = strlen(dllName);
memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section
pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk;
pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
return stringLength;
}
void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk)
{
PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor;
pImportDescriptor++;
pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk;
pImportDescriptor->Name = oldID->Name;
}
void ImportRebuild::calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
DWORD_PTR lastRVA = 0;
numberOfImportDescriptors = 0;
sizeOfImportSection = 0;
sizeOfApiAndModuleNames = 0;
numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR);
sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva)
{
numberOfImportDescriptors++; //add additional import desc
}
if((*mapIt2).second.name[0] != '\0')
{
sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME
sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1);
}
lastRVA = (*mapIt2).second.rva;
}
}
sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
\ No newline at end of file
diff --git a/Scylla/ImportRebuild.h b/Scylla/ImportRebuild.h
index f4fff23..27bad7f 100644
--- a/Scylla/ImportRebuild.h
+++ b/Scylla/ImportRebuild.h
@@ -1,71 +1,73 @@
#pragma once
+#include <map>
#include "ProcessAccessHelp.h"
#include "Thunks.h"
-class ImportRebuild {
+class ImportRebuild
+{
public:
ImportRebuild();
~ImportRebuild();
bool rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
//DWORD convertRVAToOffset(DWORD dwRVA);
//DWORD convertOffsetToRVA(DWORD dwOffset);
bool addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData);
bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size);
private:
std::vector<IMAGE_SECTION_HEADER> vecSectionHeaders;
std::vector<BYTE *> vecSectionData;
BYTE * imageData;
size_t sizeOfFile;
BYTE * pDosStub;
IMAGE_DOS_HEADER DosHeader;
IMAGE_NT_HEADERS NTHeader;
BYTE * pOverlay;
size_t sizeOfOverlay;
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
PIMAGE_THUNK_DATA pThunkData;
PIMAGE_IMPORT_BY_NAME pImportByName;
size_t numberOfImportDescriptors;
size_t sizeOfImportSection;
size_t sizeOfApiAndModuleNames;
size_t importSectionIndex;
DWORD getOffsetLastSection();
void updatePeHeader();
DWORD fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
bool splitTargetFile();
DWORD convertRVAToOffsetVector(DWORD dwRVA);
DWORD_PTR convertOffsetToRVAVector(DWORD dwOffset);
BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA);
DWORD alignValue(DWORD badValue, DWORD alignTo);
bool alignSectionHeaders();
bool saveNewFile(const WCHAR * filepath);
bool loadTargetFile(const WCHAR * filepath);
bool createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
bool buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
void setFlagToIATSection( DWORD_PTR iatAddress );
size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset);
size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset);
void calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk);
};
\ No newline at end of file
diff --git a/Scylla/MainGui.h b/Scylla/MainGui.h
index 592ba90..abc758e 100644
--- a/Scylla/MainGui.h
+++ b/Scylla/MainGui.h
@@ -1,301 +1,295 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include "multitree.h"
#include "hexedit.h"
-//#define _CRTDBG_MAP_ALLOC
-//#include <cstdlib>
-//#include <crtdbg.h>
-
-//#include <cstdio>
-
#include "Logger.h"
#include "ProcessLister.h"
#include "IATSearch.h"
#include "PickDllGui.h"
#include "ImportsHandling.h"
class MainGui : public CDialogImpl<MainGui>, public CWinDataExchange<MainGui>, public CDialogResize<MainGui>, public CMessageFilter
{
public:
enum { IDD = IDD_DLG_MAIN };
// Dialog Data eXchange, attaches/subclasses child controls to wrappers
// DDX_CONTROL : subclass
// DDX_CONTROL_HANDLE : attach
BEGIN_DDX_MAP(MainGui)
DDX_CONTROL(IDC_TREE_IMPORTS, TreeImportsSubclass) // needed for message reflection
DDX_CONTROL(IDC_TREE_IMPORTS, TreeImports)
DDX_CONTROL_HANDLE(IDC_CBO_PROCESSLIST, ComboProcessList)
DDX_CONTROL_HANDLE(IDC_LIST_LOG, ListLog)
DDX_CONTROL(IDC_EDIT_OEPADDRESS, EditOEPAddress)
DDX_CONTROL(IDC_EDIT_IATADDRESS, EditIATAddress)
DDX_CONTROL(IDC_EDIT_IATSIZE, EditIATSize)
END_DDX_MAP()
// Our message map
// Messages are passed from top to bottom
// The first handler that doesn't call SetMsgHandled(FALSE) aborts the chain
// If none signals the message as handled, it will be passed to mixins (CHAIN_MSG_MAP)
// or ultimately passed to DefWindowProc
BEGIN_MSG_MAP_EX(MainGui)
MSG_WM_INITDIALOG(OnInitDialog)
MSG_WM_DESTROY(OnDestroy)
MSG_WM_SIZE(OnSize)
MSG_WM_CONTEXTMENU(OnContextMenu)
MSG_WM_COMMAND(OnCommand)
NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, NM_DBLCLK, OnTreeImportsDoubleClick)
NOTIFY_HANDLER_EX(IDC_TREE_IMPORTS, TVN_KEYDOWN, OnTreeImportsKeyDown)
COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_DROPDOWN, OnProcessListDrop)
COMMAND_HANDLER_EX(IDC_CBO_PROCESSLIST, CBN_SELENDOK, OnProcessListSelected)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL, OnPickDLL)
COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS, OnOptions)
COMMAND_ID_HANDLER_EX(IDC_BTN_DUMP, OnDump)
COMMAND_ID_HANDLER_EX(IDC_BTN_FIXDUMP, OnFixDump)
COMMAND_ID_HANDLER_EX(IDC_BTN_PEREBUILD, OnPERebuild)
COMMAND_ID_HANDLER_EX(IDC_BTN_IATAUTOSEARCH, OnIATAutoSearch)
COMMAND_ID_HANDLER_EX(IDC_BTN_GETIMPORTS, OnGetImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_INVALIDIMPORTS, OnInvalidImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_SUSPECTIMPORTS, OnSuspectImports)
COMMAND_ID_HANDLER_EX(IDC_BTN_CLEARIMPORTS, OnClearImports)
COMMAND_ID_HANDLER_EX(ID_FILE_DUMP, OnDump)
COMMAND_ID_HANDLER_EX(ID_FILE_PEREBUILD, OnPERebuild)
COMMAND_ID_HANDLER_EX(ID_FILE_FIXDUMP, OnFixDump)
COMMAND_ID_HANDLER_EX(ID_FILE_EXIT, OnExit)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWINVALID, OnInvalidImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SHOWSUSPECT, OnSuspectImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_INVALIDATESELECTED, OnInvalidateSelected)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_CUTSELECTED, OnCutSelected)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_CLEARIMPORTS, OnClearImports)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_SAVETREE, OnSaveTree)
COMMAND_ID_HANDLER_EX(ID_IMPORTS_LOADTREE, OnLoadTree)
COMMAND_ID_HANDLER_EX(ID_TRACE_AUTOTRACE, OnAutotrace)
COMMAND_ID_HANDLER_EX(ID_MISC_DLLINJECTION, OnDLLInject)
COMMAND_ID_HANDLER_EX(ID_MISC_OPTIONS, OnOptions)
COMMAND_ID_HANDLER_EX(ID_HELP_ABOUT, OnAbout)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit)
REFLECT_NOTIFY_ID(IDC_TREE_IMPORTS) // pass WM_NOTIFY to child control
CHAIN_MSG_MAP(CDialogResize<MainGui>)
// Message map for subclassed treeview
// CContainedWindow forwards all messages to this map
ALT_MSG_MAP(IDC_TREE_IMPORTS)
MSG_WM_GETDLGCODE(OnTreeImportsSubclassGetDlgCode)
MSG_WM_CHAR(OnTreeImportsSubclassChar)
END_MSG_MAP()
// Dialog resize 'table'
// States if child controls move or resize or center in a specific direction
// when the parent dialog is resized
BEGIN_DLGRESIZE_MAP(MainGui)
DLGRESIZE_CONTROL(IDC_GROUP_ATTACH, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_CBO_PROCESSLIST, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL, DLSZ_MOVE_X)
DLGRESIZE_CONTROL(IDC_GROUP_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_TREE_IMPORTS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BTN_INVALIDIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_SUSPECTIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_CLEARIMPORTS, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_IATINFO, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_OEPADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_IATADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_IATSIZE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_OEPADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_IATADDRESS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_IATSIZE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_IATAUTOSEARCH, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_GETIMPORTS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_ACTIONS, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_AUTOTRACE, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_DUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_DUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PEREBUILD, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_FIXDUMP, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_GROUP_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_LIST_LOG, DLSZ_MOVE_Y | DLSZ_SIZE_X)
END_DLGRESIZE_MAP()
MainGui();
//void addTextToOutputLog(const WCHAR * text);
//CWindow getLogListboxHandle() const { return ListLog; }
protected:
// Variables
WCHAR stringBuffer[600];
ImportsHandling importsHandling;
//ProcessAccessHelp processAccessHelp;
ApiReader apiReader;
Process * selectedProcess;
// File selection filters
static const WCHAR filterExe[];
static const WCHAR filterDll[];
static const WCHAR filterExeDll[];
static const WCHAR filterTxt[];
static const WCHAR filterXml[];
// Controls
CMultiSelectTreeViewCtrl TreeImports;
CComboBox ComboProcessList;
CHexEdit<DWORD_PTR> EditOEPAddress;
CHexEdit<DWORD_PTR> EditIATAddress;
CHexEdit<DWORD> EditIATSize;
CListBox ListLog;
CStatusBarCtrl StatusBar;
enum StatusParts {
PART_COUNT = 0,
PART_INVALID,
PART_IMAGEBASE,
PART_MODULE
};
CContainedWindow TreeImportsSubclass;
// Handles
CIcon hIcon;
CMenu hMenuImports;
CMenu hMenuLog;
CAccelerator accelerators;
CIcon hIconCheck;
CIcon hIconWarning;
CIcon hIconError;
static const int MenuImportsOffsetTrace = 2;
static const int MenuImportsTraceOffsetScylla = 2;
static const int MenuImportsTraceOffsetImpRec = 4;
static const int PLUGIN_MENU_BASE_ID = 0x10;
protected:
virtual BOOL PreTranslateMessage(MSG* pMsg);
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
void OnDestroy();
void OnSize(UINT nType, CSize size);
void OnContextMenu(CWindow wnd, CPoint point);
void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl);
// WM_NOTIFY handlers
LRESULT OnTreeImportsDoubleClick(const NMHDR* pnmh);
LRESULT OnTreeImportsKeyDown(const NMHDR* pnmh);
// Forwarded messages from subclassed treeview
UINT OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg);
void OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags);
// WM_COMMAND handlers
void OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDump(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl);
// GUI functions
bool showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter = NULL, const WCHAR * defExtension = NULL, const WCHAR * directory = NULL);
void setupStatusBar();
void updateStatusBar();
void fillProcessListComboBox(CComboBox& hCombo);
void setIconAndDialogCaption();
void enableDialogControls(BOOL value);
CTreeItem findTreeItem(CPoint pt, bool screenCoordinates);
// Actions
void pickDllActionHandler();
void pickApiActionHandler(CTreeItem item);
void processSelectedActionHandler(int index);
void showInvalidImportsActionHandler();
void showSuspectImportsActionHandler();
void deleteSelectedImportsActionHandler();
void invalidateSelectedImportsActionHandler();
void loadTreeActionHandler();
void saveTreeActionHandler();
void iatAutosearchActionHandler();
void getImportsActionHandler();
void dumpActionHandler();
void peRebuildActionHandler();
void startDisassemblerGui(CTreeItem selectedTreeNode);
void dumpFixActionHandler();
void showAboutDialog();
void dllInjectActionHandler();
void optionsActionHandler();
void clearImportsActionHandler();
void pluginActionHandler(int menuItem);
// Popup menu functions
void SetupImportsMenuItems(CTreeItem item);
void appendPluginListToMenu(CMenuHandle hMenuTrackPopup);
void DisplayContextMenuImports(CWindow, CPoint);
void DisplayContextMenuLog(CWindow, CPoint);
// Log
void clearOutputLog();
bool saveLogToFile(const WCHAR * file);
// Misc
bool getCurrentModulePath(TCHAR * buffer, size_t bufferSize);
};
diff --git a/Scylla/PeDump.h b/Scylla/PeDump.h
index 6f0bcfd..6f7785e 100644
--- a/Scylla/PeDump.h
+++ b/Scylla/PeDump.h
@@ -1,63 +1,67 @@
+#pragma once
#include <windows.h>
-class PeDump {
+class PeDump
+{
public:
+
DWORD_PTR entryPoint; //VA
DWORD_PTR imageBase; //VA
DWORD sizeOfImage;
WCHAR fullpath[MAX_PATH];
//Settings
static bool useHeaderFromDisk;
static bool appendOverlayData;
PeDump()
{
imageBase = 0;
sizeOfImage = 0;
dumpData = 0;
headerData = 0;
pNTHeader = 0;
pDOSHeader = 0;
pSectionHeader = 0;
}
~PeDump()
{
if (dumpData != 0)
{
delete [] dumpData;
}
if (headerData != 0)
{
delete [] headerData;
}
}
bool dumpCompleteProcessToDisk(const WCHAR * dumpFilePath);
bool saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize);
bool copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize);
bool appendOverlayDataToDump(const WCHAR * dumpFilePath);
bool getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize);
private:
+
BYTE * dumpData;
BYTE * headerData;
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_NT_HEADERS pNTHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
bool validateHeaders();
bool fillPeHeaderStructs(bool fromDisk);
void fixDump(BYTE * dumpBuffer);
void fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead);
void fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead);
void fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead);
-};
\ No newline at end of file
+};
diff --git a/Scylla/PeRebuild.cpp b/Scylla/PeRebuild.cpp
index 0d50ec6..a8ea49a 100644
--- a/Scylla/PeRebuild.cpp
+++ b/Scylla/PeRebuild.cpp
@@ -1,736 +1,732 @@
#include "PeRebuild.h"
#include <imagehlp.h>
-#pragma comment(lib,"imagehlp.lib")
-
#include "ProcessAccessHelp.h"
-
#include "Scylla.h"
-//#include "ConfigurationHolder.h"
//#define DEBUG_COMMENTS
bool PeRebuild::truncateFile(WCHAR * szFilePath, DWORD dwNewFsize)
{
bool retValue = true;
HANDLE hFile = CreateFile(szFilePath,GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
if (SetFilePointer(hFile, dwNewFsize, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
{
if (GetLastError() == NO_ERROR)
{
retValue = true;
}
else
{
retValue = false;
}
}
else
{
retValue = true;
}
if (!SetEndOfFile(hFile))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"SetEndOfFile failed error %d", GetLastError());
#endif
retValue = false;
}
CloseHandle(hFile);
return retValue;
}
DWORD PeRebuild::validAlignment(DWORD BadSize)
{
div_t DivRes;
DivRes = div(BadSize, FileAlignmentConstant);
if (DivRes.rem == 0)
return BadSize;
return ((DivRes.quot+1) * FileAlignmentConstant);
}
DWORD PeRebuild::validAlignmentNew(DWORD badAddress)
{
DWORD moduloResult = badAddress % FileAlignmentConstant;
if (moduloResult)
{
return (FileAlignmentConstant - moduloResult);
}
else
{
return 0;
}
}
bool PeRebuild::isRoundedTo(DWORD_PTR dwTarNum, DWORD_PTR dwRoundNum)
{
return (dwTarNum % dwRoundNum) == 0;
// WTF:
/*
#ifdef _WIN64
lldiv_t d;
d = div((__int64)dwTarNum, (__int64)dwRoundNum);
#else
ldiv_t d;
d = div((long)dwTarNum, (long)dwRoundNum);
#endif
return (d.rem == 0);
*/
}
void PeRebuild::cleanSectionPointer()
{
if (pSections)
{
for (int j = 0; j < MAX_SEC_NUM; j++)
{
if (pSections[j])
{
free(pSections[j]);
pSections[j] = 0;
}
}
}
}
DWORD PeRebuild::realignPE(LPVOID AddressOfMapFile, DWORD dwFsize)
{
PIMAGE_DOS_HEADER pDosh = 0;
PIMAGE_NT_HEADERS pPeh = 0;
PIMAGE_SECTION_HEADER pSectionh = 0;
int i = 0;
DWORD extraAlign = 0;
ZeroMemory(&pSections, sizeof(pSections));
// get the other parameters
pMap = AddressOfMapFile;
dwMapBase = (DWORD_PTR)pMap;
if (dwFsize == 0 || pMap == NULL)
return 1;
// access the PE Header and check whether it's a valid one
pDosh = (PIMAGE_DOS_HEADER)(pMap);
pPeh = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh+pDosh->e_lfanew);
if (!validatePeHeaders(pDosh))
{
return 0;
}
if (pPeh->FileHeader.NumberOfSections > MAX_SEC_NUM)
{
return 3;
}
__try
{
/* START */
pPeh->OptionalHeader.FileAlignment = FileAlignmentConstant;
/* Realign the PE Header */
// get the size of all headers
dwTmpNum = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pPeh->FileHeader.SizeOfOptionalHeader + (pPeh->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
// kill room between the "win32 pls" message and the PE signature
// find the end of the message
pW = (WORD*)(dwMapBase + ScanStartDS);
while (*pW != 0 || (!isRoundedTo((DWORD_PTR)pW, 0x10)))
{
pW = (WORD*)((DWORD_PTR)pW + 1);
}
wTmpNum = (WORD)((DWORD_PTR)pW - dwMapBase);
if (wTmpNum < pDosh->e_lfanew)
{
CopyMemory((LPVOID)pW,(VOID*)pPeh,dwTmpNum); // copy the Header to the right place
pDosh->e_lfanew = wTmpNum;
}
dwSectionBase = validAlignment(dwTmpNum + pDosh->e_lfanew);
pPeh = (PIMAGE_NT_HEADERS)(dwMapBase + pDosh->e_lfanew); // because the NT header moved
// correct the SizeOfHeaders
pPeh->OptionalHeader.SizeOfHeaders = dwSectionBase;
/* Realign all sections */
// make a copy of all sections
// this is needed if the sections aren't sorted by their RawOffset (e.g. Petite)
pSectionh = IMAGE_FIRST_SECTION(pPeh);
for (i=0; i<pPeh->FileHeader.NumberOfSections; i++)
{
if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0)
{
++pSectionh;
continue;
}
// get a valid size
dwTmpNum = pSectionh->SizeOfRawData;
if ((pSectionh->SizeOfRawData + pSectionh->PointerToRawData) > dwFsize)
{
dwTmpNum = dwFsize - pSectionh->PointerToRawData;
}
//dwTmpNum -= 1;
// copy the section into some memory
// limit max section size to 300 MB = 300000 KB = 300000000 B
if (dwTmpNum > 300000000)
{
dwTmpNum = 300000000;
}
//because of validAlignment we need some extra space, max 0x200 extra
extraAlign = validAlignmentNew(dwTmpNum);
pSections[i] = malloc(dwTmpNum + extraAlign);
ZeroMemory(pSections[i], dwTmpNum + extraAlign);
if (pSections[i] == NULL) // fatal error !!!
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"realignPE :: malloc failed with dwTmpNum %08X %08X", dwTmpNum, extraAlign);
#endif
cleanSectionPointer();
return 4;
}
CopyMemory(pSections[i],(LPVOID)(pSectionh->PointerToRawData+dwMapBase),dwTmpNum);
++pSectionh;
}
// start realigning the sections
pSectionh = IMAGE_FIRST_SECTION(pPeh);
for (i=0;i<pPeh->FileHeader.NumberOfSections;i++)
{
// some anti crash code :P
if (pSectionh->SizeOfRawData == 0 || pSectionh->PointerToRawData == 0)
{
++pSectionh;
if (pSectionh->PointerToRawData == 0)
{
continue;
}
pSectionh->PointerToRawData = dwSectionBase;
continue;
}
// let pCH point to the end of the current section
if ((pSectionh->PointerToRawData+pSectionh->SizeOfRawData) <= dwFsize)
{
pCH = (char*)(dwMapBase+pSectionh->PointerToRawData+pSectionh->SizeOfRawData-1);
}
else
{
pCH = (char*)(dwMapBase+dwFsize-1);
}
// look for the end of this section
while (*pCH == 0)
{
--pCH;
}
// calculate the new RawSize
dwTmpNum = (DWORD)(((DWORD_PTR)pCH - dwMapBase) + MinSectionTerm - pSectionh->PointerToRawData);
if (dwTmpNum < pSectionh->SizeOfRawData)
{
pSectionh->SizeOfRawData = dwTmpNum;
}
else // the new size is too BIG
{
dwTmpNum = pSectionh->SizeOfRawData;
}
// copy the section to the new place
if (i != pPeh->FileHeader.NumberOfSections-1)
{
dwTmpNum = validAlignment(dwTmpNum);
}
CopyMemory((LPVOID)(dwMapBase+dwSectionBase), pSections[i], dwTmpNum);
// set the RawOffset
pSectionh->PointerToRawData = dwSectionBase;
// get the RawOffset for the next section
dwSectionBase = dwTmpNum+dwSectionBase; // the last section doesn't need to be aligned
// go to the next section
++pSectionh;
}
// delete bound import directories because it is destroyed if present
pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
pPeh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
// clean up
cleanSectionPointer();
}
__except(1)
{
// clean up
cleanSectionPointer();
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"realignPE :: Exception occured");
#endif
return 0;
}
if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue())
{
updatePeHeaderChecksum(AddressOfMapFile, dwSectionBase);
}
return dwSectionBase; // return the new filesize
}
// returns:
// -1 - access violation
// -2 - no relocation found
// -3 - no own section
// -4 - dll characteristics found
// -5 - invalid PE file
// else the new raw size
DWORD PeRebuild::wipeReloc(void* pMap, DWORD dwFsize)
{
PIMAGE_DOS_HEADER pDosH;
PIMAGE_NT_HEADERS pNTH;
PIMAGE_SECTION_HEADER pSecH;
PIMAGE_SECTION_HEADER pSH, pSH2;
DWORD dwRelocRVA, i;
BOOL bOwnSec = FALSE;
DWORD dwNewFsize;
__try // =)
{
// get pe header pointers
pDosH = (PIMAGE_DOS_HEADER)pMap;
if (pDosH->e_magic != IMAGE_DOS_SIGNATURE)
return -5;
pNTH = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosH + pDosH->e_lfanew);
if (pNTH->Signature != IMAGE_NT_SIGNATURE)
return -5;
pSecH = IMAGE_FIRST_SECTION(pNTH);
// has PE dll characteristics ?
if (pNTH->FileHeader.Characteristics & IMAGE_FILE_DLL)
return -4;
// is there a reloc section ?
dwRelocRVA = pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
if (!dwRelocRVA)
return -2;
// check whether the relocation has an own section
pSH = pSecH;
for (i=0; i < pNTH->FileHeader.NumberOfSections; i++)
{
if (pSH->VirtualAddress == dwRelocRVA)
{
bOwnSec = TRUE;
break; // pSH -> reloc section header and i == section index
}
++pSH;
}
if (!bOwnSec)
return -3;
if (i+1 == pNTH->FileHeader.NumberOfSections)
{
//--- relocation is the last section ---
// truncate at the start of the reloc section
dwNewFsize = pSH->PointerToRawData;
}
else
{
//--- relocation isn't the last section ---
dwNewFsize = dwFsize - pSH->SizeOfRawData;
//-> copy the section(s) after the relocation to the start of the relocation
pSH2 = pSH;
++pSH2; // pSH2 -> pointer to first section after relocation
memcpy(
(void*)(pSH->PointerToRawData + (DWORD)pMap),
(const void*)(pSH2->PointerToRawData + (DWORD)pMap),
dwFsize - pSH2->PointerToRawData);
//-> fix the section headers
// (pSH -> reloc section header)
// (pSH2 -> first section after reloc section)
for (++i; i < pNTH->FileHeader.NumberOfSections; i++)
{
// apply important values
pSH->SizeOfRawData = pSH2->SizeOfRawData;
pSH->VirtualAddress = pSH2->VirtualAddress;
pSH->Misc.VirtualSize = pSH2->Misc.VirtualSize;
// apply section name
memcpy(
(void*)(pSH->Name),
(const void*)(pSH2->Name),
sizeof(pSH2->Name));
++pSH;
++pSH2;
}
}
// dec section number
--pNTH->FileHeader.NumberOfSections;
// kill reloc directory entry
pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0;
pNTH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = 0;
// fix virtual parts of the PE Header (a must for win2k)
pSH2 = pSH = pSecH;
++pSH2;
for (i=0; i < (DWORD)pNTH->FileHeader.NumberOfSections-1; i++)
{
pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress;
++pSH;
++pSH2;
}
// (pSH -> pointer to last section)
if (pSH->Misc.PhysicalAddress)
pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->Misc.VirtualSize;
else // WATCOM is always a bit special >:-)
pNTH->OptionalHeader.SizeOfImage = pSH->VirtualAddress + pSH->SizeOfRawData;
}
__except(1)
{
// an access violation occurred :(
return -1;
}
return dwNewFsize;
}
bool PeRebuild::validatePE(void* pPEImage, DWORD dwFileSize)
{
PIMAGE_NT_HEADERS pNTh;
PIMAGE_SECTION_HEADER pSech,pSH, pSH2, pLastSH;
UINT i;
DWORD dwHeaderSize;
// get PE base information
pNTh = ImageNtHeader(pPEImage);
if (!pNTh)
return FALSE;
pSech = IMAGE_FIRST_SECTION(pNTh);
// FIX:
// ... the SizeOfHeaders
pSH = pSech;
dwHeaderSize = 0xFFFFFFFF;
for(i=0; i < pNTh->FileHeader.NumberOfSections; i++)
{
if (pSH->PointerToRawData && pSH->PointerToRawData < dwHeaderSize)
{
dwHeaderSize = pSH->PointerToRawData;
}
++pSH;
}
pNTh->OptionalHeader.SizeOfHeaders = dwHeaderSize;
// ...Virtual Sizes
pSH2 = pSH = pSech;
++pSH2;
for (i=0; i < (DWORD)pNTh->FileHeader.NumberOfSections-1; i++)
{
pSH->Misc.VirtualSize = pSH2->VirtualAddress - pSH->VirtualAddress;
++pSH;
++pSH2;
}
// (pSH -> pointer to last section)
pLastSH = pSH;
// ...RawSize of the last section
pLastSH->SizeOfRawData = dwFileSize - pLastSH->PointerToRawData;
// ...SizeOfImage
if (pLastSH->Misc.PhysicalAddress)
{
pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->Misc.VirtualSize;
}
else // WATCOM is always a bit special >:-)
{
pNTh->OptionalHeader.SizeOfImage = pLastSH->VirtualAddress + pLastSH->SizeOfRawData;
}
return true;
}
ReBaseErr PeRebuild::reBasePEImage(void* pPE, DWORD_PTR dwNewBase)
{
PIMAGE_NT_HEADERS pNT;
PIMAGE_RELOCATION pR;
ReBaseErr ret;
DWORD_PTR dwDelta;
DWORD *pdwAddr, dwRva, dwType;
UINT iItems, i;
WORD *pW;
// dwNewBase valid ?
if (dwNewBase & 0xFFFF)
{
ret = RB_INVALIDNEWBASE;
goto Exit; // ERR
}
//
// get relocation dir ptr
//
pNT = ImageNtHeader(pPE);
if (!pNT)
{
ret = RB_INVALIDPE;
goto Exit; // ERR
}
// new base = old base ?
if (pNT->OptionalHeader.ImageBase == dwNewBase)
{
ret = RB_OK;
goto Exit; // OK
}
if (!pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
{
ret = RB_NORELOCATIONINFO;
goto Exit; // ERR
}
pR = (PIMAGE_RELOCATION)ImageRvaToVa(
pNT,
pPE,
pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
NULL);
if (!pR)
{
ret = RB_INVALIDRVA;
goto Exit; // ERR
}
//
// add delta to relocation items
//
dwDelta = dwNewBase - pNT->OptionalHeader.ImageBase;
__try
{
do
{
// get number of items
if (pR->SymbolTableIndex)
iItems = (pR->SymbolTableIndex - 8) / 2;
else
break; // no items in this block
// trace/list block items...
pW = (WORD*)((DWORD_PTR)pR + 8);
for (i = 0; i < iItems; i++)
{
dwRva = (*pW & 0xFFF) + pR->VirtualAddress;
dwType = *pW >> 12;
if (dwType != 0) // fully compatible ???
{
// add delta
pdwAddr = (PDWORD)ImageRvaToVa(
pNT,
pPE,
dwRva,
NULL);
if (!pdwAddr)
{
ret = RB_INVALIDRVA;
goto Exit; // ERR
}
*pdwAddr += dwDelta;
}
// next item
++pW;
}
pR = (PIMAGE_RELOCATION)pW; // pR -> next block header
} while ( *(DWORD*)pW );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ret = RB_ACCESSVIOLATION;
goto Exit; // ERR
}
// apply new base to header
pNT->OptionalHeader.ImageBase = dwNewBase;
ret = RB_OK; // OK
Exit:
return ret;
}
bool PeRebuild::updatePeHeaderChecksum(LPVOID AddressOfMapFile, DWORD dwFsize)
{
PIMAGE_NT_HEADERS32 pNTHeader32 = 0;
PIMAGE_NT_HEADERS64 pNTHeader64 = 0;
DWORD headerSum = 0;
DWORD checkSum = 0;
pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(AddressOfMapFile, dwFsize, &headerSum, &checkSum);
if (!pNTHeader32)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"updatePeHeaderChecksum :: CheckSumMappedFile failed error %X", GetLastError());
#endif
return false;
}
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Old checksum %08X new checksum %08X", headerSum, checkSum);
#endif
if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32;
pNTHeader64->OptionalHeader.CheckSum = checkSum;
}
else
{
pNTHeader32->OptionalHeader.CheckSum = checkSum;
}
return true;
}
LPVOID PeRebuild::createFileMappingViewFull(const WCHAR * filePath)
{
hFileToMap = CreateFile(filePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if( hFileToMap == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, NULL);
if( hMappedFile == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingViewFull :: hMappedFile == NULL");
#endif
CloseHandle(hFileToMap);
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS");
#endif
CloseHandle(hFileToMap);
hMappedFile = 0;
hFileToMap = 0;
addrMappedDll = 0;
return NULL;
}
addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if(!addrMappedDll)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
#endif
CloseHandle(hFileToMap);
CloseHandle(hMappedFile);
hMappedFile = 0;
hFileToMap = 0;
return NULL;
}
return addrMappedDll;
}
void PeRebuild::closeAllMappingHandles()
{
if (addrMappedDll)
{
if (!FlushViewOfFile(addrMappedDll, 0))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"closeAllMappingHandles :: Could not flush memory to disk (%d)", GetLastError());
#endif
}
UnmapViewOfFile(addrMappedDll);
addrMappedDll = 0;
}
if (hMappedFile)
{
CloseHandle(hMappedFile);
hMappedFile = 0;
}
if (hFileToMap)
{
CloseHandle(hFileToMap);
hFileToMap = 0;
}
}
bool PeRebuild::validatePeHeaders( PIMAGE_DOS_HEADER pDosh )
{
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDosh + pDosh->e_lfanew);
if ((pDosh != 0) && (pDosh->e_magic == IMAGE_DOS_SIGNATURE) && (pNTHeader->Signature == IMAGE_NT_SIGNATURE))
{
#ifdef _WIN64
if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
#else
if (pNTHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
#endif
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
diff --git a/Scylla/PeRebuild.h b/Scylla/PeRebuild.h
index a180cf4..032eb43 100644
--- a/Scylla/PeRebuild.h
+++ b/Scylla/PeRebuild.h
@@ -1,62 +1,66 @@
+#pragma once
+
#include <Windows.h>
-#include <stdlib.h>
+#include <cstdlib>
-typedef enum _ReBaseErr
+enum ReBaseErr
{
RB_OK = 0,
RB_INVALIDPE,
RB_NORELOCATIONINFO,
RB_INVALIDRVA,
RB_INVALIDNEWBASE,
RB_ACCESSVIOLATION
-} ReBaseErr;
-
-class PeRebuild {
+};
/*****************************************************************************
Improved Realign DLL version 1.5 by yoda
*****************************************************************************/
+
+class PeRebuild
+{
public:
+
bool truncateFile(WCHAR * szFilePath, DWORD dwNewFsize);
DWORD realignPE(LPVOID AddressOfMapFile,DWORD dwFsize);
DWORD wipeReloc(void* pMap, DWORD dwFsize);
bool validatePE(void* pPEImage, DWORD dwFileSize);
ReBaseErr reBasePEImage(void* pPE, DWORD_PTR dwNewBase);
bool updatePeHeaderChecksum(LPVOID AddressOfMapFile, DWORD dwFsize);
LPVOID createFileMappingViewFull(const WCHAR * filePath);
void closeAllMappingHandles();
-
private:
+
// constants
-#define MAX_SEC_NUM 30
+ static const size_t MAX_SEC_NUM = 30;
- const static DWORD ScanStartDS = 0x40;
- const static int MinSectionTerm = 5;
- const static int FileAlignmentConstant = 0x200;
+ static const DWORD ScanStartDS = 0x40;
+ static const int MinSectionTerm = 5;
+ static const int FileAlignmentConstant = 0x200;
// variables
DWORD_PTR dwMapBase;
LPVOID pMap;
DWORD dwTmpNum,dwSectionBase;
WORD wTmpNum;
CHAR * pCH;
WORD * pW;
DWORD * pDW;
LPVOID pSections[MAX_SEC_NUM];
//my vars
HANDLE hFileToMap;
HANDLE hMappedFile;
LPVOID addrMappedDll;
DWORD validAlignment(DWORD BadSize);
DWORD validAlignmentNew(DWORD badAddress);
bool isRoundedTo(DWORD_PTR dwTarNum, DWORD_PTR dwRoundNum);
void cleanSectionPointer();
bool validatePeHeaders( PIMAGE_DOS_HEADER pDosh );
-};
\ No newline at end of file
+};
diff --git a/Scylla/PickApiGui.h b/Scylla/PickApiGui.h
index a8f8e19..912fa4b 100644
--- a/Scylla/PickApiGui.h
+++ b/Scylla/PickApiGui.h
@@ -1,94 +1,94 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include <vector>
-#include "ProcessAccessHelp.h"
+#include "ProcessAccessHelp.h" // ModuleInfo, ApiInfo
class PickApiGui : public CDialogImpl<PickApiGui>, public CWinDataExchange<PickApiGui>, public CDialogResize<PickApiGui>
{
public:
enum { IDD = IDD_DLG_PICKAPI };
BEGIN_DDX_MAP(PickApiGui)
DDX_CONTROL_HANDLE(IDC_CBO_DLLSELECT, ComboDllSelect)
DDX_CONTROL_HANDLE(IDC_LIST_APISELECT, ListApiSelect)
DDX_CONTROL_HANDLE(IDC_EDIT_APIFILTER, EditApiFilter)
END_DDX_MAP()
BEGIN_MSG_MAP(PickDllGui)
MSG_WM_INITDIALOG(OnInitDialog)
COMMAND_HANDLER_EX(IDC_CBO_DLLSELECT, CBN_SELENDOK, OnDllListSelected)
COMMAND_HANDLER_EX(IDC_LIST_APISELECT, LBN_DBLCLK, OnApiListDoubleClick)
COMMAND_HANDLER_EX(IDC_EDIT_APIFILTER, EN_UPDATE, OnApiFilterUpdated)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKAPI_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKAPI_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDialogResize<PickApiGui>)
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(PickApiGui)
DLGRESIZE_CONTROL(IDC_GROUP_DLL, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_CBO_DLLSELECT, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_GROUP_APIS, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_LIST_APISELECT, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_APIFILTER, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_APIFILTER, DLSZ_MOVE_Y | DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BTN_PICKAPI_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKAPI_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
PickApiGui(const std::vector<ModuleInfo> &moduleList);
ApiInfo* getSelectedApi() const { return selectedApi; }
protected:
// Variables
const std::vector<ModuleInfo> &moduleList;
ApiInfo* selectedApi;
// Controls
CComboBox ComboDllSelect;
CListBox ListApiSelect;
CEdit EditApiFilter;
protected:
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnDllListSelected(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnApiListDoubleClick(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnApiFilterUpdated(UINT uNotifyCode, int nID, CWindow wndCtl);
// Actions
void actionApiSelected();
// GUI functions
void fillDllComboBox(CComboBox& combo);
void fillApiListBox(CListBox& list, const std::vector<ApiInfo *> &apis);
};
diff --git a/Scylla/PickDllGui.h b/Scylla/PickDllGui.h
index 1814440..99fd1e5 100644
--- a/Scylla/PickDllGui.h
+++ b/Scylla/PickDllGui.h
@@ -1,89 +1,89 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include <vector>
-#include "ProcessAccessHelp.h"
+#include "ProcessAccessHelp.h" // ModuleInfo
class PickDllGui : public CDialogImpl<PickDllGui>, public CWinDataExchange<PickDllGui>, public CDialogResize<PickDllGui>
{
public:
enum { IDD = IDD_DLG_PICKDLL };
BEGIN_DDX_MAP(PickDllGui)
DDX_CONTROL_HANDLE(IDC_LIST_DLLSELECT, ListDLLSelect)
END_DDX_MAP()
BEGIN_MSG_MAP(PickDllGui)
MSG_WM_INITDIALOG(OnInitDialog)
NOTIFY_HANDLER_EX(IDC_LIST_DLLSELECT, LVN_COLUMNCLICK, OnListDllColumnClicked)
NOTIFY_HANDLER_EX(IDC_LIST_DLLSELECT, NM_DBLCLK, OnListDllDoubleClick)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_BTN_PICKDLL_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDialogResize<PickDllGui>)
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(PickDllGui)
DLGRESIZE_CONTROL(IDC_LIST_DLLSELECT, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_PICKDLL_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
PickDllGui(std::vector<ModuleInfo> &moduleList);
ModuleInfo* getSelectedModule() const { return selectedModule; }
protected:
// Variables
std::vector<ModuleInfo> &moduleList;
ModuleInfo* selectedModule;
// Controls
CListViewCtrl ListDLLSelect;
enum ListColumns {
COL_NAME = 0,
COL_IMAGEBASE,
COL_IMAGESIZE,
COL_PATH
};
int prevColumn;
bool ascending;
protected:
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
LRESULT OnListDllColumnClicked(NMHDR* pnmh);
LRESULT OnListDllDoubleClick(NMHDR* pnmh);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
// GUI functions
void addColumnsToModuleList(CListViewCtrl& list);
void displayModuleList(CListViewCtrl& list);
static int CALLBACK listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
};
diff --git a/Scylla/PluginLoader.cpp b/Scylla/PluginLoader.cpp
index f39a829..3e03b8c 100644
--- a/Scylla/PluginLoader.cpp
+++ b/Scylla/PluginLoader.cpp
@@ -1,361 +1,360 @@
#include "PluginLoader.h"
#include "Logger.h"
#include "ProcessAccessHelp.h"
+#include "StringConversion.h"
#include <shlwapi.h>
-#include <stdio.h>
const WCHAR PluginLoader::PLUGIN_DIR[] = L"Plugins\\";
const WCHAR PluginLoader::PLUGIN_SEARCH_STRING[] = L"*.dll";
const WCHAR PluginLoader::PLUGIN_IMPREC_DIR[] = L"ImpRec_Plugins\\";
const WCHAR PluginLoader::PLUGIN_IMPREC_WRAPPER_DLL[] = L"Imprec_Wrapper_DLL.dll";
//#define DEBUG_COMMENTS
std::vector<Plugin> & PluginLoader::getScyllaPluginList()
{
return scyllaPluginList;
}
std::vector<Plugin> & PluginLoader::getImprecPluginList()
{
return imprecPluginList;
}
bool PluginLoader::findAllPlugins()
{
if (!scyllaPluginList.empty())
{
scyllaPluginList.clear();
}
if (!imprecPluginList.empty())
{
imprecPluginList.clear();
}
if (!buildSearchString())
{
return false;
}
if (!searchForPlugin(scyllaPluginList, dirSearchString, true))
{
return false;
}
#ifndef _WIN64
if (!buildSearchStringImprecPlugins())
{
return false;
}
if (!searchForPlugin(imprecPluginList, dirSearchString, false))
{
return false;
}
#endif
return true;
}
bool PluginLoader::searchForPlugin(std::vector<Plugin> & newPluginList, const WCHAR * searchPath, bool isScyllaPlugin)
{
WIN32_FIND_DATA ffd;
HANDLE hFind = 0;
DWORD dwError = 0;
Plugin pluginData;
hFind = FindFirstFile(searchPath, &ffd);
dwError = GetLastError();
if (dwError == ERROR_FILE_NOT_FOUND)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: No files found");
#endif
return true;
}
if (hFind == INVALID_HANDLE_VALUE)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: FindFirstFile failed %d", dwError);
#endif
return false;
}
do
{
if ( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
if ((ffd.nFileSizeHigh != 0) || (ffd.nFileSizeLow < 200))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: Plugin invalid file size: %s", ffd.cFileName);
#endif
}
else
{
pluginData.fileSize = ffd.nFileSizeLow;
wcscpy_s(pluginData.fullpath, _countof(baseDirPath), baseDirPath);
wcscat_s(pluginData.fullpath, _countof(baseDirPath), ffd.cFileName);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAllPlugins :: Plugin %s", pluginData.fullpath);
#endif
if (isValidDllFile(pluginData.fullpath))
{
if (isScyllaPlugin)
{
if (getScyllaPluginName(&pluginData))
{
//add valid plugin
newPluginList.push_back(pluginData);
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"Cannot get scylla plugin name %s", pluginData.fullpath);
#endif
}
}
else
{
if (isValidImprecPlugin(pluginData.fullpath))
{
wcscpy_s(pluginData.pluginName, MAX_PATH, ffd.cFileName);
newPluginList.push_back(pluginData);
}
}
}
}
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
FindClose(hFind);
if (dwError == ERROR_NO_MORE_FILES)
{
return true;
}
else
{
return false;
}
}
bool PluginLoader::getScyllaPluginName(Plugin * pluginData)
{
bool retValue = false;
char * pluginName = 0;
- size_t convertedChars = 0;
def_ScyllaPluginNameW ScyllaPluginNameW = 0;
def_ScyllaPluginNameA ScyllaPluginNameA = 0;
HMODULE hModule = LoadLibraryEx(pluginData->fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain
if (hModule)
{
ScyllaPluginNameW = (def_ScyllaPluginNameW)GetProcAddress(hModule, "ScyllaPluginNameW");
if (ScyllaPluginNameW)
{
wcscpy_s(pluginData->pluginName, MAX_PATH, ScyllaPluginNameW());
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: Plugin name %s", pluginData->pluginName);
#endif
retValue = true;
}
else
{
ScyllaPluginNameA = (def_ScyllaPluginNameA)GetProcAddress(hModule, "ScyllaPluginNameA");
if (ScyllaPluginNameA)
{
pluginName = ScyllaPluginNameA();
- mbstowcs_s(&convertedChars, pluginData->pluginName, strlen(pluginName) + 1, pluginName, _TRUNCATE);
+ StringConversion::ToUTF16(pluginName, pluginData->pluginName, _countof(pluginData->pluginName));
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: Plugin name mbstowcs_s %s", pluginData->pluginName);
#endif
- if (convertedChars > 1)
+ if (wcslen(pluginData->pluginName) > 1)
{
retValue = true;
}
else
{
retValue = false;
}
}
else
{
retValue = false;
}
}
FreeLibrary(hModule);
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getPluginName :: LoadLibraryEx failed %s", pluginData->fullpath);
#endif
return false;
}
}
bool PluginLoader::buildSearchString()
{
ZeroMemory(dirSearchString, sizeof(dirSearchString));
ZeroMemory(baseDirPath, sizeof(baseDirPath));
if (!GetModuleFileName(0, dirSearchString, _countof(dirSearchString)))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"buildSearchString :: GetModuleFileName failed %d", GetLastError());
#endif
return false;
}
//wprintf(L"dirSearchString 1 %s\n\n", dirSearchString);
PathRemoveFileSpec(dirSearchString);
//wprintf(L"dirSearchString 2 %s\n\n", dirSearchString);
PathAppend(dirSearchString, PLUGIN_DIR);
wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString);
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_SEARCH_STRING);
//wprintf(L"dirSearchString 3 %s\n\n", dirSearchString);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"dirSearchString final %s", dirSearchString);
#endif
return true;
}
bool PluginLoader::isValidDllFile( const WCHAR * fullpath )
{
BYTE * data = 0;
DWORD lpNumberOfBytesRead = 0;
PIMAGE_DOS_HEADER pDos = 0;
PIMAGE_NT_HEADERS pNT = 0;
bool retValue = false;
HANDLE hFile = CreateFile(fullpath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
data = new BYTE[sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100];
if (ReadFile(hFile, data, sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + 0x100, &lpNumberOfBytesRead, 0))
{
pDos = (PIMAGE_DOS_HEADER)data;
if (pDos->e_magic == IMAGE_DOS_SIGNATURE)
{
pNT = (PIMAGE_NT_HEADERS)((DWORD_PTR)pDos + pDos->e_lfanew);
if (pNT->Signature == IMAGE_NT_SIGNATURE)
{
#ifdef _WIN64
if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
#else
if (pNT->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
#endif
{
retValue = true;
}
}
}
}
delete [] data;
CloseHandle(hFile);
}
return retValue;
}
bool PluginLoader::isValidImprecPlugin(const WCHAR * fullpath)
{
def_Imprec_Trace Imprec_Trace = 0;
bool retValue = false;
HMODULE hModule = LoadLibraryEx(fullpath, 0, DONT_RESOLVE_DLL_REFERENCES); //do not call DllMain
if (hModule)
{
Imprec_Trace = (def_Imprec_Trace)GetProcAddress(hModule, "Trace");
if (Imprec_Trace)
{
retValue = true;
}
else
{
retValue = false;
}
FreeLibrary(hModule);
return retValue;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"isValidImprecPlugin :: LoadLibraryEx failed %s", pluginData->fullpath);
#endif
return false;
}
}
bool PluginLoader::buildSearchStringImprecPlugins()
{
wcscpy_s(dirSearchString, _countof(dirSearchString), baseDirPath);
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_IMPREC_DIR);
wcscpy_s(baseDirPath, _countof(baseDirPath), dirSearchString);
//build imprec wrapper dll path
wcscpy_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), dirSearchString);
wcscat_s(imprecWrapperDllPath, _countof(imprecWrapperDllPath), PLUGIN_IMPREC_WRAPPER_DLL);
if (!fileExists(imprecWrapperDllPath))
{
return false;
}
wcscat_s(dirSearchString, _countof(dirSearchString), PLUGIN_SEARCH_STRING);
return true;
}
bool PluginLoader::fileExists(const WCHAR * fileName)
{
if (GetFileAttributesW(fileName) == INVALID_FILE_ATTRIBUTES)
{
return false;
}
else
{
return true;
}
}
diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp
index 01e1464..cfb7f3d 100644
--- a/Scylla/ProcessAccessHelp.cpp
+++ b/Scylla/ProcessAccessHelp.cpp
@@ -1,715 +1,715 @@
#include "ProcessAccessHelp.h"
-#include "Logger.h"
+#include "Scylla.h"
#include "NativeWinApi.h"
HANDLE ProcessAccessHelp::hProcess = 0;
ModuleInfo * ProcessAccessHelp::selectedModule;
DWORD_PTR ProcessAccessHelp::targetImageBase = 0;
DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0;
DWORD_PTR ProcessAccessHelp::maxValidAddress = 0;
std::vector<ModuleInfo> ProcessAccessHelp::moduleList; //target process module list
std::vector<ModuleInfo> ProcessAccessHelp::ownModuleList; //own module list
_DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS];
unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0;
_CodeInfo ProcessAccessHelp::decomposerCi = {0};
_DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS];
unsigned int ProcessAccessHelp::decodedInstructionsCount = 0;
BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
//#define DEBUG_COMMENTS
bool ProcessAccessHelp::openProcessHandle(DWORD dwPID)
{
if (dwPID > 0)
{
if (hProcess)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess);
#endif
return false;
}
else
{
//hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID);
//if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid)))
hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, dwPID);
if (hProcess)
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID);
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID);
#endif
return false;
}
}
HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId)
{
HANDLE hProcess = 0;
CLIENT_ID cid = {0};
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS ntStatus = 0;
InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0);
cid.UniqueProcess = (HANDLE)dwProcessId;
ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid);
if (NT_SUCCESS(ntStatus))
{
return hProcess;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus));
#endif
return 0;
}
}
void ProcessAccessHelp::closeProcessHandle()
{
CloseHandle(hProcess);
hProcess = 0;
moduleList.clear();
targetImageBase = 0;
selectedModule = 0;
}
bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
{
SIZE_T lpNumberOfBytesRead = 0;
DWORD dwProtect = 0;
bool returnValue = false;
if (!hProcess)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL");
#endif
return returnValue;
}
if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
{
if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError());
#endif
returnValue = false;
}
else
{
if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
#endif
returnValue = false;
}
else
{
returnValue = true;
}
VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect);
}
}
else
{
returnValue = true;
}
if (returnValue)
{
if (size != lpNumberOfBytesRead)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size);
#endif
returnValue = false;
}
else
{
returnValue = true;
}
}
return returnValue;
}
bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress)
{
ZeroMemory(&decomposerCi, sizeof(_CodeInfo));
decomposerCi.code = dataBuffer;
decomposerCi.codeLen = (int)bufferSize;
decomposerCi.dt = dt;
decomposerCi.codeOffset = startAddress;
decomposerInstructionsCount = 0;
if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR");
#endif
return false;
}
else
{
return true;
}
}
bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset)
{
// Holds the result of the decoding.
_DecodeResult res;
// next is used for instruction's offset synchronization.
// decodedInstructionsCount holds the count of filled instructions' array by the decoder.
decodedInstructionsCount = 0;
_OffsetType offset = startOffset;
res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount);
/* for (unsigned int i = 0; i < decodedInstructionsCount; i++) {
#ifdef SUPPORT_64BIT_OFFSET
printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
#else
printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
#endif
}*/
if (res == DECRES_INPUTERR)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR");
#endif
return false;
}
else if (res == DECRES_SUCCESS)
{
//printf("disassembleMemory :: res == DECRES_SUCCESS\n");
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"disassembleMemory :: res == %d", res);
#endif
return false;
}
}
DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask)
{
DWORD pos = 0;
size_t searchLen = strlen(mask) - 1;
for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++)
{
if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' )
{
if(mask[pos+1] == 0x00)
{
return (retAddress - searchLen);
}
pos++;
} else {
pos = 0;
}
}
return 0;
}
bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath)
{
return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath);
}
LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath)
{
LONGLONG fileSize = 0;
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
fileSize = getFileSize(hFile);
CloseHandle(hFile);
hFile = 0;
}
return fileSize;
}
LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile)
{
LARGE_INTEGER lpFileSize = {0};
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
if (!GetFileSizeEx(hFile, &lpFileSize))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError());
#endif
return 0;
}
else
{
return lpFileSize.QuadPart;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid");
#endif
return 0;
}
}
bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer)
{
DWORD lpNumberOfBytesRead = 0;
DWORD retValue = 0;
DWORD dwError = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
dwError = GetLastError();
if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError);
#endif
return false;
}
else
{
if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer)
{
DWORD lpNumberOfBytesWritten = 0;
DWORD retValue = 0;
DWORD dwError = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
dwError = GetLastError();
if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError);
#endif
return false;
}
else
{
if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer)
{
DWORD lpNumberOfBytesWritten = 0;
DWORD retValue = 0;
if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
{
SetFilePointer(hFile, 0, 0, FILE_END);
if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
{
return true;
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError());
#endif
return false;
}
}
else
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid");
#endif
return false;
}
}
bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath)
{
DWORD lpNumberOfBytesRead = 0;
LONGLONG fileSize = 0;
DWORD dwSize = 0;
bool returnValue = 0;
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if( hFile == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
returnValue = false;
}
else
{
fileSize = getFileSize(hFile);
if (fileSize > 0)
{
if (fileSize > bufferSize)
{
dwSize = bufferSize;
}
else
{
dwSize = (DWORD)(fileSize - 1);
}
returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer);
}
CloseHandle(hFile);
}
return returnValue;
}
LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath)
{
return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ);
}
LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath)
{
return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS);
}
LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap)
{
HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if( hFile == INVALID_HANDLE_VALUE )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
#endif
return NULL;
}
HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL);
CloseHandle(hFile);
if( hMappedFile == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL");
#endif
return NULL;
}
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS);
#endif
return NULL;
}
LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0);
if( addrMappedDll == NULL )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
#endif
CloseHandle(hMappedFile);
return NULL;
}
CloseHandle(hMappedFile);
return addrMappedDll;
}
DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName)
{
DWORD dwPID = 0;
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32W pe32;
pe32.dwSize = sizeof(PROCESSENTRY32W);
if( !Process32FirstW( hProcessSnap, &pe32 ) )
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getProcessByName :: Error getting first Process");
#endif
CloseHandle( hProcessSnap );
return 0;
}
do
{
if(!_wcsicmp(pe32.szExeFile, processName))
{
dwPID = pe32.th32ProcessID;
break;
}
} while(Process32NextW(hProcessSnap, &pe32));
CloseHandle(hProcessSnap);
return dwPID;
}
bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
ModuleInfo module;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return false;
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module,
// and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap );
return false;
}
// Now walk the module list of the process,
// and display information about each module
//the first is always the .exe
if (!Module32Next(hModuleSnap, &me32))
{
CloseHandle( hModuleSnap );
return false;
}
moduleList.reserve(20);
do
{
//printf(L"\n MODULE NAME: %s", me32.szModule);
module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr;
module.modBaseSize = me32.modBaseSize;
module.isAlreadyParsed = false;
module.parsing = false;
wcscpy_s(module.fullPath, MAX_PATH, me32.szExePath);
moduleList.push_back(module);
} while(Module32Next(hModuleSnap, &me32));
CloseHandle( hModuleSnap );
return true;
}
bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize)
{
MEMORY_BASIC_INFORMATION memBasic;
if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError());
#endif
return false;
}
else
{
*memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress;
*memoryRegionSize = memBasic.RegionSize;
return true;
}
}
bool ProcessAccessHelp::getSizeOfImageCurrentProcess()
{
DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase);
if (newSizeOfImage != 0)
{
ProcessAccessHelp::targetSizeOfImage = newSizeOfImage;
return true;
}
else
{
return false;
}
}
SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase)
{
SIZE_T sizeOfImage = 0;
MEMORY_BASIC_INFORMATION lpBuffer = {0};
SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION);
do
{
moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize);
sizeOfImage += lpBuffer.RegionSize;
//printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage);
if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError());
#endif
lpBuffer.Type = 0;
sizeOfImage = 0;
}
/*else
{
printf("\nAllocationBase %X\n",lpBuffer.AllocationBase);
printf("AllocationProtect %X\n",lpBuffer.AllocationProtect);
printf("BaseAddress %X\n",lpBuffer.BaseAddress);
printf("Protect %X\n",lpBuffer.Protect);
printf("RegionSize %X\n",lpBuffer.RegionSize);
printf("State %X\n",lpBuffer.State);
printf("Type %X\n",lpBuffer.Type);
}*/
} while (lpBuffer.Type == MEM_IMAGE);
//printf("Real sizeOfImage %X\n",sizeOfImage);
return sizeOfImage;
}
DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath)
{
PIMAGE_NT_HEADERS pNtHeader = 0;
PIMAGE_DOS_HEADER pDosHeader = 0;
readHeaderFromCurrentFile(filePath);
pDosHeader = (PIMAGE_DOS_HEADER)fileHeaderFromDisk;
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
pNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileHeaderFromDisk + (DWORD_PTR)(pDosHeader->e_lfanew));
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
return pNtHeader->OptionalHeader.AddressOfEntryPoint;
}
bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath)
{
size_t fileNameLength = wcslen(filePath) + 5; //.bak + null
BOOL retValue = 0;
WCHAR * backupFile = new WCHAR[fileNameLength];
wcscpy_s(backupFile, fileNameLength, filePath);
wcscat_s(backupFile, fileNameLength, L".bak");
retValue = CopyFile(filePath, backupFile, FALSE);
if (!retValue)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError());
#endif
}
delete [] backupFile;
return retValue != 0;
}
diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h
index 5eb3a93..a219673 100644
--- a/Scylla/ProcessAccessHelp.h
+++ b/Scylla/ProcessAccessHelp.h
@@ -1,202 +1,206 @@
#pragma once
-#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>
-#include <hash_map>
-#include <map>
+#include <vector>
/************************************************************************/
/* distorm */
/************************************************************************/
-#include "distorm.h"
+#include <distorm.h>
// The number of the array of instructions the decoder function will use to return the disassembled instructions.
// Play with this value for performance...
#define MAX_INSTRUCTIONS (200)
/************************************************************************/
class ApiInfo;
-class ModuleInfo {
+class ModuleInfo
+{
public:
+
WCHAR fullPath[MAX_PATH];
DWORD_PTR modBaseAddr;
DWORD modBaseSize;
bool isAlreadyParsed;
bool parsing;
/*
for iat rebuilding with duplicate entries:
ntdll = low priority
kernelbase = low priority
SHLWAPI = low priority
kernel32 = high priority
priority = 1 -> normal/high priority
priority = 0 -> low priority
*/
int priority;
std::vector<ApiInfo *> apiList;
ModuleInfo()
{
modBaseAddr = 0;
modBaseSize = 0;
priority = 1;
isAlreadyParsed = false;
parsing = false;
}
const WCHAR * getFilename() const
{
const WCHAR* slash = wcsrchr(fullPath, L'\\');
if(slash)
{
return slash+1;
}
return fullPath;
}
};
-class ApiInfo {
- public:
- char name[MAX_PATH];
- WORD hint;
- DWORD_PTR va;
- DWORD_PTR rva;
- WORD ordinal;
- bool isForwarded;
- ModuleInfo * module;
+class ApiInfo
+{
+public:
+
+ char name[MAX_PATH];
+ WORD hint;
+ DWORD_PTR va;
+ DWORD_PTR rva;
+ WORD ordinal;
+ bool isForwarded;
+ ModuleInfo * module;
};
-class ProcessAccessHelp {
+class ProcessAccessHelp
+{
public:
+
static HANDLE hProcess; //OpenProcess handle to target process
static DWORD_PTR targetImageBase;
static DWORD_PTR targetSizeOfImage;
static DWORD_PTR maxValidAddress;
static ModuleInfo * selectedModule;
static std::vector<ModuleInfo> moduleList; //target process module list
static std::vector<ModuleInfo> ownModuleList; //own module list
- static const int PE_HEADER_BYTES_COUNT = 2000;
+ static const size_t PE_HEADER_BYTES_COUNT = 2000;
static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
//for decomposer
static _DInst decomposerResult[MAX_INSTRUCTIONS];
static unsigned int decomposerInstructionsCount;
static _CodeInfo decomposerCi;
//distorm :: Decoded instruction information.
static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS];
static unsigned int decodedInstructionsCount;
#ifdef _WIN64
static const _DecodeType dt = Decode64Bits;
#else
static const _DecodeType dt = Decode32Bits;
#endif
/*
* Open a new process handle
*/
static bool openProcessHandle(DWORD dwPID);
static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId);
static void closeProcessHandle();
/*
* Get all modules from a process
*/
static bool getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList);
/*
* file mapping view with different access level
*/
static LPVOID createFileMappingViewRead(const WCHAR * filePath);
static LPVOID createFileMappingViewFull(const WCHAR * filePath);
/*
* Create a file mapping view of a file
*/
static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap);
/*
* Read memory from target process
*/
static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer);
/*
* Read memory from file
*/
static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer);
/*
* Write memory to file
*/
static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer);
/*
* Write memory to file end
*/
static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer);
/*
* Disassemble Memory
*/
static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset);
static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress);
/*
* Search for pattern
*/
static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask);
/*
* Get process ID by process name
*/
static DWORD getProcessByName(const WCHAR * processName);
/*
* Get memory region from address
*/
static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize);
/*
* Read PE Header from file
*/
static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath);
static bool readHeaderFromCurrentFile(const WCHAR * filePath);
/*
* Get real sizeOfImage value
*/
static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase);
/*
* Get real sizeOfImage value current process
*/
static bool getSizeOfImageCurrentProcess();
static LONGLONG getFileSize(HANDLE hFile);
static LONGLONG getFileSize(const WCHAR * filePath);
static DWORD getEntryPointFromFile(const WCHAR * filePath);
static bool createBackupFile(const WCHAR * filePath);
};
diff --git a/Scylla/ProcessLister.h b/Scylla/ProcessLister.h
index 4a61362..a93630e 100644
--- a/Scylla/ProcessLister.h
+++ b/Scylla/ProcessLister.h
@@ -1,73 +1,70 @@
#pragma once
#include <windows.h>
#include <tlhelp32.h>
#include <vector>
-#include <Psapi.h>
-
-#pragma comment(lib, "Psapi.lib")
-
+#include <psapi.h>
typedef BOOL (WINAPI *def_IsWow64Process)(HANDLE hProcess,PBOOL Wow64Process);
class Process {
public:
DWORD PID;
DWORD_PTR imageBase;
DWORD entryPoint; //without imagebase
DWORD imageSize;
WCHAR filename[MAX_PATH];
WCHAR fullPath[MAX_PATH];
Process()
{
PID = 0;
}
};
class HardDisk {
public:
WCHAR shortName[3];
WCHAR longName[MAX_PATH];
size_t longNameLength;
};
enum ProcessType {
PROCESS_UNKNOWN,
PROCESS_MISSING_RIGHTS,
PROCESS_32,
PROCESS_64
};
class ProcessLister {
public:
static def_IsWow64Process _IsWow64Process;
ProcessLister()
{
initDeviceNameList();
_IsWow64Process = (def_IsWow64Process)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process");
}
std::vector<Process>& getProcessList();
static bool isWindows64();
static DWORD setDebugPrivileges();
std::vector<Process>& ProcessLister::getProcessListSnapshot();
private:
std::vector<Process> processList;
std::vector<HardDisk> deviceNameList;
ProcessType checkIsProcess64(DWORD dwPID);
void initDeviceNameList();
bool getAbsoluteFilePath(Process * process);
void getAllModuleInformation();
void getModuleInformationByProcess(Process *process);
bool resolveDeviceLongNameToShort( WCHAR * sourcePath, WCHAR * targetPath );
};
\ No newline at end of file
diff --git a/Scylla/SystemInformation.cpp b/Scylla/SystemInformation.cpp
index da8918d..efc9f1c 100644
--- a/Scylla/SystemInformation.cpp
+++ b/Scylla/SystemInformation.cpp
@@ -1,76 +1,76 @@
#include "SystemInformation.h"
OPERATING_SYSTEM SystemInformation::currenOS = UNKNOWN_OS;
bool SystemInformation::getSystemInformation()
{
OSVERSIONINFOEX osvi = {0};
SYSTEM_INFO si = {0};
def_GetNativeSystemInfo _GetNativeSystemInfo = 0;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!GetVersionEx((OSVERSIONINFO*) &osvi))
{
return false;
}
if ((osvi.dwMajorVersion < 5) || ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)))
{
return false;
}
_GetNativeSystemInfo = (def_GetNativeSystemInfo)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetNativeSystemInfo");
if (_GetNativeSystemInfo)
{
_GetNativeSystemInfo(&si);
}
else
{
GetSystemInfo(&si);
}
bool isX64 = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
bool isX86 = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
DWORD major = osvi.dwMajorVersion;
DWORD minor = osvi.dwMinorVersion;
if(isX64 && major == 5 && minor == 2)
{
currenOS = WIN_XP_64;
}
else if(isX86 && major == 5 && minor == 1)
{
currenOS = WIN_XP_32;
}
- if(isX64 && major == 6 && minor == 0)
+ else if(isX64 && major == 6 && minor == 0)
{
currenOS = WIN_VISTA_64;
}
else if(isX86 && major == 6 && minor == 0)
{
currenOS = WIN_VISTA_32;
}
else if(isX64 && major == 6 && minor == 1)
{
currenOS = WIN_7_64;
}
else if(isX86 && major == 6 && minor == 1)
{
currenOS = WIN_7_32;
}
else if(isX64 && major == 6 && minor == 2)
{
currenOS = WIN_8_64;
}
else if(isX86 && major == 6 && minor == 2)
{
currenOS = WIN_8_32;
}
else
{
currenOS = UNKNOWN_OS;
}
return (currenOS != UNKNOWN_OS);
}
diff --git a/Scylla/SystemInformation.h b/Scylla/SystemInformation.h
index e687a6a..aef7f69 100644
--- a/Scylla/SystemInformation.h
+++ b/Scylla/SystemInformation.h
@@ -1,24 +1,25 @@
#pragma once
#include <windows.h>
enum OPERATING_SYSTEM {
UNKNOWN_OS,
WIN_XP_32,
WIN_XP_64,
WIN_VISTA_32,
WIN_VISTA_64,
WIN_7_32,
WIN_7_64,
WIN_8_32,
WIN_8_64
};
typedef void (WINAPI *def_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
-class SystemInformation {
+class SystemInformation
+{
public:
+
static OPERATING_SYSTEM currenOS;
static bool getSystemInformation();
-private:
};
diff --git a/Scylla/Thunks.h b/Scylla/Thunks.h
index 9cb935b..5c31d19 100644
--- a/Scylla/Thunks.h
+++ b/Scylla/Thunks.h
@@ -1,44 +1,43 @@
#pragma once
#include <windows.h>
-#include <Commctrl.h>
#include <map>
// WTL
#include <atlbase.h>
#include <atlapp.h>
-#include <atlctrls.h> //CTreeItem
+#include <atlctrls.h> // CTreeItem
class ImportThunk
{
public:
WCHAR moduleName[MAX_PATH];
char name[MAX_PATH];
DWORD_PTR va;
DWORD_PTR rva;
WORD ordinal;
DWORD_PTR apiAddressVA;
WORD hint;
bool valid;
bool suspect;
CTreeItem hTreeItem;
DWORD_PTR key;
void invalidate();
};
class ImportModuleThunk
{
public:
WCHAR moduleName[MAX_PATH];
std::map<DWORD_PTR, ImportThunk> thunkList;
DWORD_PTR firstThunk;
CTreeItem hTreeItem;
DWORD_PTR key;
DWORD_PTR getFirstThunk() const;
bool isValid() const;
};
diff --git a/Scylla/TreeImportExport.cpp b/Scylla/TreeImportExport.cpp
index a6cf3e2..43eb64c 100644
--- a/Scylla/TreeImportExport.cpp
+++ b/Scylla/TreeImportExport.cpp
@@ -1,346 +1,337 @@
-
#include "TreeImportExport.h"
#include "Architecture.h"
#include "Scylla.h"
-
-#define DEBUG_COMMENTS
+#include "StringConversion.h"
bool TreeImportExport::exportTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT)
{
TiXmlDocument doc;
- TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
+ TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "");
doc.LinkEndChild(decl);
TiXmlElement * rootElement = new TiXmlElement("target");
setTargetInformation(rootElement, process,addressOEP,addressIAT,sizeIAT);
addModuleListToRootElement(rootElement, moduleList);
doc.LinkEndChild(rootElement);
return saveXmlToFile(doc,targetXmlFile);
}
bool TreeImportExport::importTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR * addressOEP, DWORD_PTR * addressIAT, DWORD * sizeIAT)
{
TiXmlElement * targetElement;
TiXmlDocument doc;
char * buffer = readXmlFile(targetXmlFile);
int count = 0;
moduleList.clear();
if (buffer)
{
doc.Parse(buffer);
if (doc.Error())
{
Scylla::windowLog.log(L"Load Tree :: Error parsing xml %S: %S\r\n", doc.Value(), doc.ErrorDesc());
delete [] buffer;
return false;
}
targetElement = doc.FirstChildElement();
*addressOEP = ConvertStringToDwordPtr(targetElement->Attribute("oep_va"));
*addressIAT = ConvertStringToDwordPtr(targetElement->Attribute("iat_va"));
*sizeIAT = (DWORD)ConvertStringToDwordPtr(targetElement->Attribute("iat_size"));
//test = targetElement->Attribute("filename");
parseAllElementModules(targetElement, moduleList);
delete [] buffer;
}
return true;
}
void TreeImportExport::setTargetInformation(TiXmlElement * rootElement, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT)
{
- size_t stringLength = 0;
-
- wcstombs_s(&stringLength, xmlStringBuffer, (size_t)_countof(xmlStringBuffer), process->filename, (size_t)_countof(process->filename));
-
-
+ StringConversion::ToASCII(process->filename, xmlStringBuffer, _countof(xmlStringBuffer));
rootElement->SetAttribute("filename", xmlStringBuffer);
ConvertDwordPtrToString(addressOEP);
- rootElement->SetAttribute("oep_va",xmlStringBuffer);
+ rootElement->SetAttribute("oep_va", xmlStringBuffer);
ConvertDwordPtrToString(addressIAT);
- rootElement->SetAttribute("iat_va",xmlStringBuffer);
+ rootElement->SetAttribute("iat_va", xmlStringBuffer);
ConvertDwordPtrToString(sizeIAT);
- rootElement->SetAttribute("iat_size",xmlStringBuffer);
+ rootElement->SetAttribute("iat_size", xmlStringBuffer);
}
char * TreeImportExport::readXmlFile(const WCHAR * xmlFilePath)
{
FILE * pFile = 0;
long lSize = 0;
char * buffer = 0;
if (_wfopen_s(&pFile,xmlFilePath,L"r") == NULL)
{
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
fseek(pFile, 0, SEEK_SET);
if (lSize > 2)
{
buffer = new char[lSize + sizeof(char)];
ZeroMemory(buffer, lSize + sizeof(char));
fread(buffer, sizeof(char), lSize, pFile);
if (!feof(pFile) || ferror(pFile))
{
delete [] buffer;
buffer = 0;
}
}
fclose (pFile);
return buffer;
}
else
{
return 0;
}
}
bool TreeImportExport::saveXmlToFile(TiXmlDocument doc, const WCHAR * xmlFilePath)
{
FILE * pFile = 0;
if (_wfopen_s(&pFile,xmlFilePath,L"w") == NULL)
{
doc.Print(pFile);
fclose (pFile);
return true;
}
else
{
return false;
}
}
void TreeImportExport::addModuleListToRootElement( TiXmlElement * rootElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
ImportModuleThunk * importModuleThunk = 0;
ImportThunk * importThunk = 0;
TiXmlElement * moduleElement;
TiXmlElement * importElement;
for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
{
importModuleThunk = &((*mapIt).second);
moduleElement = getModuleXmlElement(importModuleThunk);
for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
{
importThunk = &((*mapIt2).second);
importElement = getImportXmlElement(importThunk);
moduleElement->LinkEndChild(importElement);
}
rootElement->LinkEndChild(moduleElement);
}
}
TiXmlElement * TreeImportExport::getModuleXmlElement(const ImportModuleThunk * importModuleThunk)
{
- size_t stringLength = 0;
TiXmlElement * moduleElement = new TiXmlElement("module");
- wcstombs_s(&stringLength, xmlStringBuffer, (size_t)_countof(xmlStringBuffer), importModuleThunk->moduleName, (size_t)_countof(importModuleThunk->moduleName));
-
+ StringConversion::ToASCII(importModuleThunk->moduleName, xmlStringBuffer, _countof(xmlStringBuffer));
moduleElement->SetAttribute("filename", xmlStringBuffer);
ConvertDwordPtrToString(importModuleThunk->getFirstThunk());
moduleElement->SetAttribute("first_thunk_rva",xmlStringBuffer);
return moduleElement;
}
TiXmlElement * TreeImportExport::getImportXmlElement(const ImportThunk * importThunk)
{
TiXmlElement * importElement = 0;
if (importThunk->valid)
{
importElement = new TiXmlElement("import_valid");
if(importThunk->name[0] != '\0')
{
importElement->SetAttribute("name",importThunk->name);
}
ConvertWordToString(importThunk->ordinal);
importElement->SetAttribute("ordinal",xmlStringBuffer);
ConvertWordToString(importThunk->hint);
importElement->SetAttribute("hint",xmlStringBuffer);
ConvertBoolToString(importThunk->suspect);
importElement->SetAttribute("suspect", xmlStringBuffer);
}
else
{
importElement = new TiXmlElement("import_invalid");
}
ConvertDwordPtrToString(importThunk->rva);
importElement->SetAttribute("iat_rva", xmlStringBuffer);
ConvertDwordPtrToString(importThunk->apiAddressVA);
importElement->SetAttribute("address_va",xmlStringBuffer);
return importElement;
}
void TreeImportExport::ConvertBoolToString(const bool boolValue)
{
if (boolValue)
{
- strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer),"1");
+ strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer), "1");
}
else
{
- strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer),"0");
+ strcpy_s(xmlStringBuffer,_countof(xmlStringBuffer), "0");
}
}
bool TreeImportExport::ConvertStringToBool(const char * strValue)
{
if (strValue)
{
if (strValue[0] == '1')
{
return true;
}
}
return false;
}
void TreeImportExport::ConvertDwordPtrToString(const DWORD_PTR dwValue)
{
sprintf_s(xmlStringBuffer, _countof(xmlStringBuffer), PRINTF_DWORD_PTR_FULL_S, dwValue);
}
DWORD_PTR TreeImportExport::ConvertStringToDwordPtr(const char * strValue)
{
DWORD_PTR result = 0;
if (strValue)
{
#ifdef _WIN64
result = _strtoi64(strValue, NULL, 16);
#else
result = strtoul(strValue, NULL, 16);
#endif
}
return result;
}
void TreeImportExport::ConvertWordToString(const WORD dwValue)
{
sprintf_s(xmlStringBuffer, _countof(xmlStringBuffer), "%04X", dwValue);
}
WORD TreeImportExport::ConvertStringToWord(const char * strValue)
{
WORD result = 0;
if (strValue)
{
result = (WORD)strtoul(strValue, NULL, 16);
}
return result;
}
void TreeImportExport::parseAllElementModules( TiXmlElement * targetElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
{
TiXmlElement * moduleElement = 0;
ImportModuleThunk importModuleThunk;
- size_t convertedChars = 0;
const char * filename = 0;
for(moduleElement = targetElement->FirstChildElement(); moduleElement; moduleElement = moduleElement->NextSiblingElement())
{
filename = moduleElement->Attribute("filename");
if (filename)
{
+ StringConversion::ToUTF16(filename, importModuleThunk.moduleName, _countof(importModuleThunk.moduleName));
- mbstowcs_s(&convertedChars, importModuleThunk.moduleName, _countof(importModuleThunk.moduleName), filename, _TRUNCATE);
importModuleThunk.firstThunk = ConvertStringToDwordPtr(moduleElement->Attribute("first_thunk_rva"));
importModuleThunk.thunkList.clear();
parseAllElementImports(moduleElement, &importModuleThunk);
moduleList.insert(std::pair<DWORD_PTR,ImportModuleThunk>(importModuleThunk.firstThunk, importModuleThunk));
}
}
}
void TreeImportExport::parseAllElementImports( TiXmlElement * moduleElement, ImportModuleThunk * importModuleThunk )
{
TiXmlElement * importElement = 0;
ImportThunk importThunk;
const char * temp = 0;
for(importElement = moduleElement->FirstChildElement(); importElement; importElement = importElement->NextSiblingElement())
{
temp = importElement->Value();
if (!strcmp(temp, "import_valid"))
{
temp = importElement->Attribute("name");
if (temp)
{
strcpy_s(importThunk.name, _countof(importThunk.name),temp);
}
else
{
importThunk.name[0] = 0;
}
wcscpy_s(importThunk.moduleName,_countof(importThunk.moduleName), importModuleThunk->moduleName);
importThunk.suspect = ConvertStringToBool(importElement->Attribute("suspect"));
importThunk.ordinal = ConvertStringToWord(importElement->Attribute("ordinal"));
importThunk.hint = ConvertStringToWord(importElement->Attribute("hint"));
importThunk.valid = true;
}
else
{
importThunk.valid = false;
importThunk.suspect = true;
}
importThunk.apiAddressVA = ConvertStringToDwordPtr(importElement->Attribute("address_va"));
importThunk.rva = ConvertStringToDwordPtr(importElement->Attribute("iat_rva"));
if (importThunk.rva != 0)
{
importModuleThunk->thunkList.insert(std::pair<DWORD_PTR,ImportThunk>(importThunk.rva, importThunk));
}
}
}
diff --git a/Scylla/TreeImportExport.h b/Scylla/TreeImportExport.h
index 33c3893..443807a 100644
--- a/Scylla/TreeImportExport.h
+++ b/Scylla/TreeImportExport.h
@@ -1,42 +1,38 @@
-
#pragma once
-#include <Windows.h>
+#include <windows.h>
#include "ProcessLister.h"
#include "Thunks.h"
-#include "tinyxml.h"
-
-
+#include <tinyxml.h>
class TreeImportExport
{
public:
+
bool exportTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT);
-
bool importTreeList(const WCHAR * targetXmlFile, std::map<DWORD_PTR, ImportModuleThunk> & moduleList, DWORD_PTR * addressOEP, DWORD_PTR * addressIAT, DWORD * sizeIAT);
private:
+
char xmlStringBuffer[100];
void addModuleListToRootElement( TiXmlElement * rootElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
TiXmlElement * getModuleXmlElement(const ImportModuleThunk * importModuleThunk);
TiXmlElement * getImportXmlElement(const ImportThunk * importThunk);
bool saveXmlToFile(TiXmlDocument doc, const WCHAR * xmlFilePath);
char * readXmlFile(const WCHAR * xmlFilePath);
void setTargetInformation(TiXmlElement * rootElement, const Process * process, const DWORD_PTR addressOEP, const DWORD_PTR addressIAT, const DWORD sizeIAT);
void ConvertBoolToString(const bool boolValue);
void ConvertWordToString(const WORD dwValue);
void ConvertDwordPtrToString(const DWORD_PTR dwValue);
DWORD_PTR ConvertStringToDwordPtr(const char * strValue);
WORD ConvertStringToWord(const char * strValue);
bool ConvertStringToBool(const char * strValue);
-
-
void parseAllElementModules( TiXmlElement * targetElement, std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
void parseAllElementImports( TiXmlElement * moduleElement, ImportModuleThunk * importModuleThunk );
-};
\ No newline at end of file
+};
diff --git a/Scylla/hexedit.h b/Scylla/hexedit.h
index 0e68680..dabdf6e 100644
--- a/Scylla/hexedit.h
+++ b/Scylla/hexedit.h
@@ -1,235 +1,235 @@
#pragma once
#ifndef __cplusplus
#error WTL requires C++ compilation (use a .cpp suffix)
#endif
#ifndef __ATLMISC_H__
#error hexedit.h requires atlmisc.h to be included first
#endif
#ifndef __ATLCTRLS_H__
- #error hexedit.h requires atlmisc.h to be included first requires atlctrls.h to be included first
+ #error hexedit.h requires atlctrls.h to be included first
#endif
/*
#ifdef _WIN64
address = _wcstoui64(hexString, NULL, 16);
#else
address = wcstoul(hexString, NULL, 16);
#endif
*/
template< class T, typename NUM_T, class TBase = CEdit, class TWinTraits = CControlWinTraits >
class ATL_NO_VTABLE CHexEditImpl : public CWindowImpl< T, TBase, TWinTraits >
{
public:
static const short int BASE = 16;
static const size_t DIGITS = sizeof(NUM_T) * 2; // 2 digits / byte
static const size_t STRSIZE = DIGITS + 1;
static const TCHAR Digits[];
static const TCHAR OldProcProp[];
// Operations
BOOL SubclassWindow(HWND hWnd)
{
ATLASSERT(m_hWnd == NULL);
ATLASSERT(::IsWindow(hWnd));
BOOL bRet = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
if( bRet ) _Init();
return bRet;
}
NUM_T GetValue() const
{
ATLASSERT(::IsWindow(m_hWnd));
TCHAR String[STRSIZE] = { 0 };
GetWindowText(String, _countof(String));
return _StringToNum(String);
}
void SetValue(NUM_T Num, bool Fill = true)
{
ATLASSERT(::IsWindow(m_hWnd));
TCHAR String[STRSIZE] = { 0 };
_NumToString(Num, String, Fill);
SetWindowText(String);
}
// Implementation
void _Init()
{
ATLASSERT(::IsWindow(m_hWnd));
LimitText(DIGITS);
}
bool _IsValidChar(TCHAR Char) const
{
return ((NUM_T)-1 != _CharToNum(Char));
}
bool _IsValidString(const TCHAR String[STRSIZE]) const
{
for(int i = 0; String[i]; i++)
{
if(!_IsValidChar(String[i]))
return false;
}
return true;
}
NUM_T _CharToNum(TCHAR Char) const
{
Char = _totupper(Char);
for(int i = 0; Digits[i]; i++)
{
if(Char == Digits[i])
return i;
}
return -1;
}
NUM_T _StringToNum(const TCHAR String[STRSIZE]) const
{
NUM_T CharNum;
NUM_T Num = 0;
for(int i = 0; String[i]; i++)
{
CharNum = _CharToNum(String[i]);
if(CharNum == (NUM_T)-1)
break;
Num *= BASE;
Num += CharNum;
}
return Num;
}
TCHAR _NumToChar(NUM_T Num) const
{
return Digits[Num % BASE];
}
void _NumToString(NUM_T Num, TCHAR String[STRSIZE], bool Fill) const
{
NUM_T Nums[DIGITS];
int i, j;
for(i = DIGITS-1; i >= 0; i--)
{
Nums[i] = Num % BASE;
Num /= BASE;
}
for(i = j = 0; i < DIGITS; i++)
{
// Only copy num if : non-null OR Fill OR non-null encountered before OR last num
if(Nums[i] || Fill || j || i == DIGITS-1)
{
String[j++] = _NumToChar(Nums[i]);
}
}
String[j] = '\0';
}
bool _GetClipboardText(TCHAR String[STRSIZE])
{
#ifdef UNICODE
const UINT Format = CF_UNICODETEXT;
#else
const UINT Format = CF_TEXT;
#endif
bool RetVal = false;
if(IsClipboardFormatAvailable(Format) && OpenClipboard())
{
HANDLE HMem = GetClipboardData(Format);
if(HMem)
{
_tcsncpy_s(String, STRSIZE, (TCHAR *)GlobalLock(HMem), STRSIZE-1);
String[STRSIZE-1] = '\0';
GlobalUnlock(HMem);
RetVal = true;
}
CloseClipboard();
}
return RetVal;
}
// Message map and handlers
BEGIN_MSG_MAP_EX(CHexEditImpl)
MESSAGE_HANDLER_EX(WM_CREATE, OnCreate)
MSG_WM_SETTEXT(OnSetText)
MSG_WM_PASTE(OnPaste)
MSG_WM_CHAR(OnChar)
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes = DefWindowProc();
_Init();
return lRes;
}
int OnSetText(LPCTSTR lpstrText)
{
bool PassThrough = (_tcslen(lpstrText) <= DIGITS) && _IsValidString(lpstrText);
if(!PassThrough)
{
MessageBeep(-1);
return FALSE;
}
SetMsgHandled(FALSE);
return TRUE;
}
void OnPaste()
{
TCHAR String[STRSIZE];
bool PassThrough = !_GetClipboardText(String) || _IsValidString(String);
if(!PassThrough)
{
MessageBeep(-1);
return;
}
SetMsgHandled(FALSE);
return;
}
void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// ignore all printable chars (incl. space) which are not valid digits
bool PassThrough = !_istprint((TCHAR)nChar) || _IsValidChar((TCHAR)nChar);
if(!PassThrough)
{
MessageBeep(-1);
return;
}
SetMsgHandled(FALSE);
return;
}
};
template< class T, typename NUM_T, class TBase, class TWinTraits > const TCHAR CHexEditImpl< T, NUM_T, TBase, TWinTraits >::Digits[] = _T("0123456789ABCDEF");
template<typename NUM_T> class CHexEdit : public CHexEditImpl<CHexEdit<NUM_T>, NUM_T>
{
public:
DECLARE_WND_CLASS(_T("WTL_HexEdit"))
};
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jul 5, 8:03 PM (1 d, 2 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
01/a5/91b85befbe87dbaa46e8adcef984
Attached To
rSCY Scylla
Event Timeline
Log In to Comment