Page Menu
Home
desp's stash
Search
Configure Global Search
Log In
Files
F352086
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
118 KB
Subscribers
None
View Options
diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp
index 7e6e0c6..52ab836 100644
--- a/Scylla/ConfigurationHolder.cpp
+++ b/Scylla/ConfigurationHolder.cpp
@@ -1,208 +1,205 @@
#include "ConfigurationHolder.h"
#include <shlwapi.h>
#include <stdio.h>
#include "Architecture.h"
-const WCHAR ConfigurationHolder::CONFIG_FILE_NAME[] = L"Scylla.ini";
const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG";
//#define DEBUG_COMMENTS
-ConfigurationInitializer::ConfigurationInitializer()
+ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName)
{
- ConfigObject configObject;
-
- mapConfig[USE_PE_HEADER_FROM_DISK] = configObject.newValues(L"USE_PE_HEADER_FROM_DISK", Boolean);
- mapConfig[DEBUG_PRIVILEGE] = configObject.newValues(L"DEBUG_PRIVILEGE", Boolean);
- mapConfig[CREATE_BACKUP] = configObject.newValues(L"CREATE_BACKUP", Boolean);
- mapConfig[DLL_INJECTION_AUTO_UNLOAD] = configObject.newValues(L"DLL_INJECTION_AUTO_UNLOAD", Boolean);
- mapConfig[UPDATE_HEADER_CHECKSUM] = configObject.newValues(L"UPDATE_HEADER_CHECKSUM", Boolean);
- mapConfig[IAT_SECTION_NAME] = configObject.newValues(L"IAT_SECTION_NAME", String);
+ 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<Configuration, ConfigObject>::iterator mapIter;
+ std::map<ConfigOption, Configuration>::iterator mapIter;
- if (!buildConfigFilePath())
+ if (configPath[0] == '\0')
{
return false;
}
- for (mapIter = config.mapConfig.begin() ; mapIter != config.mapConfig.end(); mapIter++)
+ for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
- if (!loadConfig((*mapIter).second))
+ Configuration& configObject = mapIter->second;
+ if (!loadConfig(configObject))
{
return false;
}
}
return true;
}
-bool ConfigurationHolder::saveConfiguration()
+bool ConfigurationHolder::saveConfiguration() const
{
- std::map<Configuration, ConfigObject>::iterator mapIter;
+ std::map<ConfigOption, Configuration>::const_iterator mapIter;
- if (!buildConfigFilePath())
+ if (configPath[0] == '\0')
{
return false;
}
- for (mapIter = config.mapConfig.begin() ; mapIter != config.mapConfig.end(); mapIter++)
+ for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
- if (!saveConfig((*mapIter).second))
+ const Configuration& configObject = mapIter->second;
+ if (!saveConfig(configObject))
{
return false;
}
}
return true;
}
-bool ConfigurationHolder::saveNumericToConfigFile(ConfigObject & configObject, int nBase)
+Configuration& ConfigurationHolder::operator[](ConfigOption option)
{
+ return config[option];
+}
- if (nBase == 16)
+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())
{
- swprintf_s(configObject.valueString, CONFIG_OPTIONS_STRING_LENGTH, PRINTF_DWORD_PTR_FULL, configObject.valueNumeric);
+ return found->second;
}
else
{
- swprintf_s(configObject.valueString, CONFIG_OPTIONS_STRING_LENGTH, PRINTF_INTEGER, configObject.valueNumeric);
+ 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.name, configObject.valueString, configPath);
+ BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), buf, configPath);
return ret == TRUE;
}
-bool ConfigurationHolder::readNumericFromConfigFile(ConfigObject & configObject, int nBase)
+bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase)
{
- DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, L"", configObject.valueString, _countof(configObject.valueString), configPath);
+ 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(configObject.valueString) > 0)
+ if (read > 0 && wcslen(buf) > 0)
{
-
#ifdef _WIN64
- configObject.valueNumeric = _wcstoui64(configObject.valueString, NULL, nBase);
+ configObject.setNumeric(_wcstoui64(buf, NULL, nBase));
#else
- configObject.valueNumeric = wcstoul(configObject.valueString, NULL, nBase);
+ configObject.setNumeric(wcstoul(buf, NULL, nBase));
#endif
-
- return (configObject.valueNumeric != 0);
- }
- else
- {
- return false;
+ return true;
}
+
+ return false;
}
-bool ConfigurationHolder::saveStringToConfigFile(ConfigObject & configObject)
+bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const
{
- BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, configObject.valueString, configPath);
+ BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath);
return ret == TRUE;
}
-bool ConfigurationHolder::readStringFromConfigFile(ConfigObject & configObject)
+bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject)
{
- DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, L"", configObject.valueString, _countof(configObject.valueString), configPath);
- return (read > 0 && wcslen(configObject.valueString) > 0);
+ 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(ConfigObject & configObject)
+bool ConfigurationHolder::readBooleanFromConfigFile(Configuration & configObject)
{
- UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.name, 0, configPath);
- configObject.valueNumeric = val ? 1 : 0;
+ UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath);
+ configObject.setBool(val != 0);
return true;
}
-bool ConfigurationHolder::saveBooleanToConfigFile(ConfigObject & configObject)
+bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const
{
- WCHAR *boolValue = 0;
-
- if (configObject.valueNumeric == 0)
- {
- boolValue = L"0";
- }
- else
- {
- boolValue = L"1";
- }
-
- BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.name, boolValue, configPath);
+ 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(ConfigObject & configObject)
+bool ConfigurationHolder::loadConfig(Configuration & configObject)
{
- switch (configObject.configType)
+ switch (configObject.getType())
{
- case String:
+ case Configuration::String:
return readStringFromConfigFile(configObject);
- break;
- case Boolean:
+ case Configuration::Boolean:
return readBooleanFromConfigFile(configObject);
- break;
- case Decimal:
+ case Configuration::Decimal:
return readNumericFromConfigFile(configObject, 10);
- break;
- case Hexadecimal:
+ case Configuration::Hexadecimal:
return readNumericFromConfigFile(configObject, 16);
- break;
default:
return false;
}
}
-bool ConfigurationHolder::saveConfig(ConfigObject & configObject)
+bool ConfigurationHolder::saveConfig(const Configuration & configObject) const
{
- switch (configObject.configType)
+ switch (configObject.getType())
{
- case String:
+ case Configuration::String:
return saveStringToConfigFile(configObject);
- break;
- case Boolean:
+ case Configuration::Boolean:
return saveBooleanToConfigFile(configObject);
- break;
- case Decimal:
+ case Configuration::Decimal:
return saveNumericToConfigFile(configObject, 10);
- break;
- case Hexadecimal:
+ case Configuration::Hexadecimal:
return saveNumericToConfigFile(configObject, 16);
- break;
default:
return false;
}
}
-ConfigObject * ConfigurationHolder::getConfigObject(Configuration configuration)
-{
- return &(config.mapConfig[configuration]);
-}
-
-bool ConfigurationHolder::buildConfigFilePath()
+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, CONFIG_FILE_NAME);
+ PathAppend(configPath, fileName);
//wprintf(L"configPath %s\n\n", configPath);
return true;
}
-
-std::map<Configuration, ConfigObject> & ConfigurationHolder::getConfigList()
-{
- return config.mapConfig;
-}
diff --git a/Scylla/ConfigurationHolder.h b/Scylla/ConfigurationHolder.h
index 498b015..174196e 100644
--- a/Scylla/ConfigurationHolder.h
+++ b/Scylla/ConfigurationHolder.h
@@ -1,94 +1,48 @@
#pragma once
#include <windows.h>
#include <map>
+#include "Configuration.h"
-enum ConfigType {
- String,
- Decimal,
- Hexadecimal,
- Boolean
-};
-
-enum Configuration {
+enum ConfigOption
+{
USE_PE_HEADER_FROM_DISK,
DEBUG_PRIVILEGE,
CREATE_BACKUP,
DLL_INJECTION_AUTO_UNLOAD,
IAT_SECTION_NAME,
UPDATE_HEADER_CHECKSUM,
};
-const size_t CONFIG_OPTIONS_STRING_LENGTH = 100;
-
-class ConfigObject {
+class ConfigurationHolder
+{
public:
- WCHAR name[MAX_PATH];
- ConfigType configType;
-
- DWORD_PTR valueNumeric;
- WCHAR valueString[CONFIG_OPTIONS_STRING_LENGTH];
-
- ConfigObject& newValues(WCHAR * configname, ConfigType config)
- {
- wcscpy_s(name, MAX_PATH, configname);
- configType = config;
- valueNumeric = 0;
- ZeroMemory(valueString, sizeof(valueString));
-
- return *this;
- }
-
- bool isTrue()
- {
- return (valueNumeric == 1);
- }
-
- void setTrue()
- {
- valueNumeric = 1;
- }
- void setFalse()
- {
- valueNumeric = 0;
- }
-};
-
-class ConfigurationInitializer {
-public:
- std::map<Configuration, ConfigObject> mapConfig;
-
- ConfigurationInitializer();
-};
-
-class ConfigurationHolder {
-public:
+ ConfigurationHolder(const WCHAR* fileName);
bool loadConfiguration();
- bool saveConfiguration();
+ bool saveConfiguration() const;
- ConfigObject * getConfigObject(Configuration configuration);
- std::map<Configuration, ConfigObject> & getConfigList();
+ Configuration& operator[](ConfigOption option);
+ const Configuration& operator[](ConfigOption option) const;
private:
- static const WCHAR CONFIG_FILE_NAME[];
static const WCHAR CONFIG_FILE_SECTION_NAME[];
- ConfigurationInitializer config;
WCHAR configPath[MAX_PATH];
+ std::map<ConfigOption, Configuration> config;
- bool buildConfigFilePath();
+ bool buildConfigFilePath(const WCHAR* fileName);
- bool readStringFromConfigFile(ConfigObject & configObject);
- bool readBooleanFromConfigFile(ConfigObject & configObject);
- bool readNumericFromConfigFile(ConfigObject & configObject, int nBase);
+ bool readStringFromConfigFile(Configuration & configObject);
+ bool readBooleanFromConfigFile(Configuration & configObject);
+ bool readNumericFromConfigFile(Configuration & configObject, int nBase);
- bool saveStringToConfigFile(ConfigObject & configObject);
- bool saveBooleanToConfigFile(ConfigObject & configObject);
- bool saveNumericToConfigFile(ConfigObject & configObject, int nBase);
+ bool saveStringToConfigFile(const Configuration & configObject) const;
+ bool saveBooleanToConfigFile(const Configuration & configObject) const;
+ bool saveNumericToConfigFile(const Configuration & configObject, int nBase) const;
- bool loadConfig(ConfigObject & configObject);
- bool saveConfig(ConfigObject & configObject);
+ bool loadConfig(Configuration & configObject);
+ bool saveConfig(const Configuration & configObject) const;
};
diff --git a/Scylla/IATSearch.cpp b/Scylla/IATSearch.cpp
index 13e6fca..7c45ca9 100644
--- a/Scylla/IATSearch.cpp
+++ b/Scylla/IATSearch.cpp
@@ -1,373 +1,371 @@
#include "IATSearch.h"
#include "Scylla.h"
#include "Architecture.h"
//#define DEBUG_COMMENTS
bool IATSearch::searchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT)
{
DWORD_PTR addressInIAT = 0;
addressInIAT = findAPIAddressInIAT(startAddress);
if(!addressInIAT)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"searchImportAddressTableInProcess :: addressInIAT not found, startAddress " PRINTF_DWORD_PTR_FULL, startAddress);
#endif
return false;
}
else
{
return findIATStartAndSize(addressInIAT, addressIAT,sizeIAT);
}
}
DWORD_PTR IATSearch::findAPIAddressInIAT(DWORD_PTR startAddress)
{
- static const int MEMORY_READ_SIZE = 200;
- BYTE *dataBuffer = new BYTE[MEMORY_READ_SIZE];
+ const size_t MEMORY_READ_SIZE = 200;
+ BYTE dataBuffer[MEMORY_READ_SIZE];
+
DWORD_PTR iatPointer = 0;
int counter = 0;
// to detect stolen api
memoryAddress = 0;
memorySize = 0;
do
{
counter++;
- if (!readMemoryFromProcess(startAddress,MEMORY_READ_SIZE,dataBuffer))
+ if (!readMemoryFromProcess(startAddress, sizeof(dataBuffer), dataBuffer))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAPIAddressInIAT :: error reading memory " PRINTF_DWORD_PTR_FULL, startAddress);
#endif
return 0;
}
- if (decomposeMemory(dataBuffer, MEMORY_READ_SIZE, startAddress))
+ if (decomposeMemory(dataBuffer, sizeof(dataBuffer), startAddress))
{
iatPointer = findIATPointer();
if (iatPointer)
{
if (isIATPointerValid(iatPointer))
{
- delete[] dataBuffer;
return iatPointer;
}
}
}
startAddress = findNextFunctionAddress();
//printf("startAddress %08X\n",startAddress);
} while (startAddress != 0 && counter != 8);
-
- delete[] dataBuffer;
return 0;
}
DWORD_PTR IATSearch::findNextFunctionAddress()
{
#ifdef DEBUG_COMMENTS
_DecodedInst inst;
#endif
for (unsigned int i = 0; i < decomposerInstructionsCount; i++)
{
if (decomposerResult[i].flags != FLAG_NOT_DECODABLE)
{
if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH)
{
if (decomposerResult[i].size >= 5)
{
if (decomposerResult[i].ops[0].type == O_PC)
{
#ifdef DEBUG_COMMENTS
distorm_format(&decomposerCi, &decomposerResult[i], &inst);
Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_TARGET(&decomposerResult[i]));
#endif
return (DWORD_PTR)INSTRUCTION_GET_TARGET(&decomposerResult[i]);
}
}
}
}
}
return 0;
}
DWORD_PTR IATSearch::findIATPointer()
{
#ifdef DEBUG_COMMENTS
_DecodedInst inst;
#endif
for (unsigned int i = 0; i < decomposerInstructionsCount; i++)
{
if (decomposerResult[i].flags != FLAG_NOT_DECODABLE)
{
if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH)
{
if (decomposerResult[i].size >= 5)
{
#ifdef _WIN64
if (decomposerResult[i].flags & FLAG_RIP_RELATIVE)
{
#ifdef DEBUG_COMMENTS
distorm_format(&decomposerCi, &decomposerResult[i], &inst);
Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i]));
#endif
return INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i]);
}
#else
if (decomposerResult[i].ops[0].type == O_DISP)
{
//jmp dword ptr || call dword ptr
#ifdef DEBUG_COMMENTS
distorm_format(&decomposerCi, &decomposerResult[i], &inst);
Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp);
#endif
return (DWORD_PTR)decomposerResult[i].disp;
}
#endif
}
}
}
}
return 0;
}
/*DWORD_PTR IATSearch::findAddressFromWORDString(char * stringBuffer)
{
char * pAddress = 0;
char * pTemp = 0;
DWORD_PTR address = 0;
//string split it e.g. DWORD [0x40f0fc], QWORD [RIP+0x40f0]
pAddress = strchr(stringBuffer, 'x');
if (pAddress)
{
pAddress++;
pTemp = strchr(pAddress, ']');
*pTemp = 0x00;
address = strtoul(pAddress, 0, 16);
//printf("findAddressFromWORDString :: %08X\n",address);
if (address == ULONG_MAX)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAddressFromDWORDString :: strtoul ULONG_MAX");
#endif
return 0;
}
else
{
return address;
}
}
else
{
return 0;
}
}*/
/*DWORD_PTR IATSearch::findAddressFromNormalCALLString(char * stringBuffer)
{
char * pAddress = 0;
DWORD_PTR address = 0;
//e.g. CALL 0x7238
pAddress = strchr(stringBuffer, 'x');
if (pAddress)
{
pAddress++;
address = strtoul(pAddress, 0, 16);
//printf("findAddressFromNormalCALLString :: %08X\n",address);
if (address == ULONG_MAX)
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findAddressFromNormalCALLString :: strtoul ULONG_MAX");
#endif
return 0;
}
else
{
return address;
}
}
else
{
return 0;
}
}*/
bool IATSearch::isIATPointerValid(DWORD_PTR iatPointer)
{
DWORD_PTR apiAddress = 0;
if (!readMemoryFromProcess(iatPointer,sizeof(DWORD_PTR),&apiAddress))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"isIATPointerValid :: error reading memory");
#endif
return false;
}
//printf("Win api ? %08X\n",apiAddress);
if (isApiAddressValid(apiAddress) != 0)
{
return true;
}
else
{
//maybe redirected import?
//if the address is 2 times inside a memory region it is possible a redirected api
if (apiAddress > memoryAddress && apiAddress < (memoryAddress+memorySize))
{
return true;
}
else
{
getMemoryRegionFromAddress(apiAddress, &memoryAddress, &memorySize);
return false;
}
}
}
bool IATSearch::findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT)
{
MEMORY_BASIC_INFORMATION memBasic = {0};
BYTE *dataBuffer = 0;
if (VirtualQueryEx(hProcess,(LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findIATStartAddress :: VirtualQueryEx error %u", GetLastError());
#endif
return false;
}
//(sizeof(DWORD_PTR) * 3) added to prevent buffer overflow
dataBuffer = new BYTE[memBasic.RegionSize + (sizeof(DWORD_PTR) * 3)];
ZeroMemory(dataBuffer, memBasic.RegionSize + (sizeof(DWORD_PTR) * 3));
if (!readMemoryFromProcess((DWORD_PTR)memBasic.BaseAddress, memBasic.RegionSize, dataBuffer))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findIATStartAddress :: error reading memory");
#endif
return false;
}
//printf("address %X memBasic.BaseAddress %X memBasic.RegionSize %X\n",address,memBasic.BaseAddress,memBasic.RegionSize);
*addressIAT = findIATStartAddress((DWORD_PTR)memBasic.BaseAddress, address, dataBuffer);
*sizeIAT = findIATSize((DWORD_PTR)memBasic.BaseAddress, *addressIAT, dataBuffer, (DWORD)memBasic.RegionSize);
delete [] dataBuffer;
return true;
}
DWORD_PTR IATSearch::findIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer)
{
DWORD_PTR *pIATAddress = 0;
pIATAddress = (DWORD_PTR *)((startAddress - baseAddress) + (DWORD_PTR)dataBuffer);
while((DWORD_PTR)pIATAddress != (DWORD_PTR)dataBuffer)
{
if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) )
{
if ( (*(pIATAddress - 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress - 1)) )
{
//IAT end
if ((DWORD_PTR)(pIATAddress - 2) >= (DWORD_PTR)dataBuffer)
{
if (!isApiAddressValid(*(pIATAddress - 2)))
{
return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress);
}
}
else
{
return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress);
}
}
}
pIATAddress--;
}
return baseAddress;
}
DWORD IATSearch::findIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize)
{
DWORD_PTR *pIATAddress = 0;
pIATAddress = (DWORD_PTR *)((iatAddress - baseAddress) + (DWORD_PTR)dataBuffer);
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findIATSize :: baseAddress %X iatAddress %X dataBuffer %X pIATAddress %X", baseAddress, iatAddress, dataBuffer, pIATAddress);
#endif
while((DWORD_PTR)pIATAddress < ((DWORD_PTR)dataBuffer + bufferSize - 1))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"findIATSize :: %X %X %X", pIATAddress, *pIATAddress, *(pIATAddress + 1));
#endif
if ( (*pIATAddress < 0xFFFF) || !isAddressAccessable(*pIATAddress) ) //normal is 0
{
if ( (*(pIATAddress + 1) < 0xFFFF) || !isAddressAccessable(*(pIATAddress + 1)) )
{
//IAT end
if (!isApiAddressValid(*(pIATAddress + 2)))
{
return (DWORD)((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer - (iatAddress - baseAddress));
}
}
}
pIATAddress++;
}
return bufferSize;
}
bool IATSearch::isAddressAccessable(DWORD_PTR address)
{
BYTE junk[3];
SIZE_T numberOfBytesRead = 0;
if (ReadProcessMemory(hProcess, (LPCVOID)address, junk, sizeof(junk), &numberOfBytesRead))
{
if (numberOfBytesRead == sizeof(junk))
{
if (junk[0] != 0x00)
{
return true;
}
}
}
return false;
}
\ No newline at end of file
diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp
index 088b109..38c56ff 100644
--- a/Scylla/ImportRebuild.cpp
+++ b/Scylla/ImportRebuild.cpp
@@ -1,715 +1,715 @@
#include "ImportRebuild.h"
#include "Scylla.h"
//#include "ConfigurationHolder.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.getConfigObject(IAT_SECTION_NAME)->valueString) > IMAGE_SIZEOF_SHORT_NAME)
+ 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.getConfigObject(IAT_SECTION_NAME)->valueString, _TRUNCATE);
+ wcstombs_s(&i, sectionName, sizeof(sectionName), Scylla::config[IAT_SECTION_NAME].getString(), _TRUNCATE);
}
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));
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/MainGui.cpp b/Scylla/MainGui.cpp
index 9825a45..1391533 100644
--- a/Scylla/MainGui.cpp
+++ b/Scylla/MainGui.cpp
@@ -1,1248 +1,1248 @@
#include "MainGui.h"
#include "Architecture.h"
//#include "PluginLoader.h"
//#include "ConfigurationHolder.h"
#include "PeDump.h"
#include "PeRebuild.h"
#include "DllInjectionPlugin.h"
#include "DisassemblerGui.h"
#include "PickApiGui.h"
//#include "NativeWinApi.h"
#include "ImportRebuild.h"
#include "SystemInformation.h"
#include "Scylla.h"
#include "AboutGui.h"
#include "OptionsGui.h"
#include "TreeImportExport.h"
extern CAppModule _Module; // o_O
const WCHAR MainGui::filterExe[] = L"Executable (*.exe)\0*.exe\0All files\0*.*\0";
const WCHAR MainGui::filterDll[] = L"Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0";
const WCHAR MainGui::filterExeDll[] = L"Executable (*.exe)\0*.exe\0Dynamic Link Library (*.dll)\0*.dll\0All files\0*.*\0";
const WCHAR MainGui::filterTxt[] = L"Text file (*.txt)\0*.txt\0All files\0*.*\0";
const WCHAR MainGui::filterXml[] = L"XML file (*.xml)\0*.xml\0All files\0*.*\0";
MainGui::MainGui() : selectedProcess(0), importsHandling(TreeImports), TreeImportsSubclass(this, IDC_TREE_IMPORTS)
{
/*
Logger::getDebugLogFilePath();
ConfigurationHolder::loadConfiguration();
PluginLoader::findAllPlugins();
NativeWinApi::initialize();
SystemInformation::getSystemInformation();
if(ConfigurationHolder::getConfigObject(DEBUG_PRIVILEGE)->isTrue())
{
processLister.setDebugPrivileges();
}
ProcessAccessHelp::getProcessModules(GetCurrentProcessId(), ProcessAccessHelp::ownModuleList);
*/
Scylla::init();
hIcon.LoadIcon(IDI_ICON_SCYLLA);
hMenuImports.LoadMenu(IDR_MENU_IMPORTS);
hMenuLog.LoadMenu(IDR_MENU_LOG);
accelerators.LoadAccelerators(IDR_ACCELERATOR_MAIN);
hIconCheck.LoadIcon(IDI_ICON_CHECK, 16, 16);
hIconWarning.LoadIcon(IDI_ICON_WARNING, 16, 16);
hIconError.LoadIcon(IDI_ICON_ERROR, 16, 16);
}
BOOL MainGui::PreTranslateMessage(MSG* pMsg)
{
if(accelerators.TranslateAccelerator(m_hWnd, pMsg))
{
return TRUE; // handled keyboard shortcuts
}
else if(IsDialogMessage(pMsg))
{
return TRUE; // handled dialog messages
}
return FALSE;
}
BOOL MainGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
{
if (SystemInformation::currenOS == UNKNOWN_OS)
{
if(IDCANCEL == MessageBox(L"Operating System is not supported\r\nContinue anyway?", L"Scylla", MB_ICONWARNING | MB_OKCANCEL))
{
SendMessage(WM_CLOSE);
return FALSE;
}
}
// register ourselves to receive PreTranslateMessage
CMessageLoop* pLoop = _Module.GetMessageLoop();
pLoop->AddMessageFilter(this);
setupStatusBar();
DoDataExchange(); // attach controls
DlgResize_Init(true, true); // init CDialogResize
Scylla::windowLog.setWindow(ListLog);
appendPluginListToMenu(hMenuImports.GetSubMenu(0));
appendPluginListToMenu(CMenuHandle(GetMenu()).GetSubMenu(MenuImportsOffsetTrace));
enableDialogControls(FALSE);
setIconAndDialogCaption();
return TRUE;
}
void MainGui::OnDestroy()
{
PostQuitMessage(0);
}
void MainGui::OnSize(UINT nType, CSize size)
{
StatusBar.SendMessage(WM_SIZE);
SetMsgHandled(FALSE);
}
void MainGui::OnContextMenu(CWindow wnd, CPoint point)
{
switch(wnd.GetDlgCtrlID())
{
case IDC_TREE_IMPORTS:
DisplayContextMenuImports(wnd, point);
return;
case IDC_LIST_LOG:
DisplayContextMenuLog(wnd, point);
return;
}
SetMsgHandled(FALSE);
}
void MainGui::OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
{
// Handle plugin trace menu selection
if(uNotifyCode == 0 && !wndCtl.IsWindow()) // make sure it's a menu
{
if ((nID >= PLUGIN_MENU_BASE_ID) && (nID <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID)))
{
pluginActionHandler(nID);
return;
}
}
SetMsgHandled(FALSE);
}
LRESULT MainGui::OnTreeImportsDoubleClick(const NMHDR* pnmh)
{
if(TreeImports.GetCount() < 1)
return 0;
// Get item under cursor
CTreeItem over = findTreeItem(CPoint(GetMessagePos()), true);
if(over && importsHandling.isImport(over))
{
pickApiActionHandler(over);
}
return 0;
}
LRESULT MainGui::OnTreeImportsKeyDown(const NMHDR* pnmh)
{
const NMTVKEYDOWN * tkd = (NMTVKEYDOWN *)pnmh;
switch(tkd->wVKey)
{
case VK_RETURN:
{
CTreeItem selected = TreeImports.GetFocusItem();
if(!selected.IsNull() && importsHandling.isImport(selected))
{
pickApiActionHandler(selected);
}
}
return 1;
case VK_DELETE:
deleteSelectedImportsActionHandler();
return 1;
}
SetMsgHandled(FALSE);
return 0;
}
UINT MainGui::OnTreeImportsSubclassGetDlgCode(const MSG * lpMsg)
{
if(lpMsg)
{
switch(lpMsg->wParam)
{
case VK_RETURN:
return DLGC_WANTMESSAGE;
}
}
SetMsgHandled(FALSE);
return 0;
}
void MainGui::OnTreeImportsSubclassChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch(nChar)
{
case VK_RETURN:
break;
default:
SetMsgHandled(FALSE);
break;
}
}
void MainGui::OnProcessListDrop(UINT uNotifyCode, int nID, CWindow wndCtl)
{
fillProcessListComboBox(ComboProcessList);
}
void MainGui::OnProcessListSelected(UINT uNotifyCode, int nID, CWindow wndCtl)
{
processSelectedActionHandler(ComboProcessList.GetCurSel());
}
void MainGui::OnPickDLL(UINT uNotifyCode, int nID, CWindow wndCtl)
{
pickDllActionHandler();
}
void MainGui::OnOptions(UINT uNotifyCode, int nID, CWindow wndCtl)
{
optionsActionHandler();
}
void MainGui::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl)
{
dumpActionHandler();
}
void MainGui::OnFixDump(UINT uNotifyCode, int nID, CWindow wndCtl)
{
dumpFixActionHandler();
}
void MainGui::OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl)
{
peRebuildActionHandler();
}
void MainGui::OnDLLInject(UINT uNotifyCode, int nID, CWindow wndCtl)
{
dllInjectActionHandler();
}
void MainGui::OnIATAutoSearch(UINT uNotifyCode, int nID, CWindow wndCtl)
{
iatAutosearchActionHandler();
}
void MainGui::OnGetImports(UINT uNotifyCode, int nID, CWindow wndCtl)
{
getImportsActionHandler();
}
void MainGui::OnInvalidImports(UINT uNotifyCode, int nID, CWindow wndCtl)
{
showInvalidImportsActionHandler();
}
void MainGui::OnSuspectImports(UINT uNotifyCode, int nID, CWindow wndCtl)
{
showSuspectImportsActionHandler();
}
void MainGui::OnClearImports(UINT uNotifyCode, int nID, CWindow wndCtl)
{
clearImportsActionHandler();
}
void MainGui::OnInvalidateSelected(UINT uNotifyCode, int nID, CWindow wndCtl)
{
invalidateSelectedImportsActionHandler();
}
void MainGui::OnCutSelected(UINT uNotifyCode, int nID, CWindow wndCtl)
{
deleteSelectedImportsActionHandler();
}
void MainGui::OnSaveTree(UINT uNotifyCode, int nID, CWindow wndCtl)
{
saveTreeActionHandler();
}
void MainGui::OnLoadTree(UINT uNotifyCode, int nID, CWindow wndCtl)
{
loadTreeActionHandler();
}
void MainGui::OnAutotrace(UINT uNotifyCode, int nID, CWindow wndCtl)
{
// TODO
}
void MainGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl)
{
DestroyWindow();
}
void MainGui::OnAbout(UINT uNotifyCode, int nID, CWindow wndCtl)
{
showAboutDialog();
}
void MainGui::setupStatusBar()
{
StatusBar.Create(m_hWnd, NULL, L"", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_TOOLTIPS, NULL, IDC_STATUS_BAR);
CRect rcMain, rcStatus;
GetClientRect(&rcMain);
StatusBar.GetWindowRect(&rcStatus);
const int PARTS = 4;
int widths[PARTS];
widths[PART_COUNT] = rcMain.Width() / 5;
widths[PART_INVALID] = widths[PART_COUNT] + rcMain.Width() / 5;
widths[PART_IMAGEBASE] = widths[PART_INVALID] + rcMain.Width() / 3;
widths[PART_MODULE] = -1;
StatusBar.SetParts(PARTS, widths);
ResizeClient(rcMain.Width(), rcMain.Height() + rcStatus.Height(), FALSE);
}
void MainGui::updateStatusBar()
{
// Rewrite ImportsHandling so we get these easily
unsigned int totalImports = importsHandling.thunkCount();
unsigned int invalidImports = importsHandling.invalidThunkCount();
// \t = center, \t\t = right-align
swprintf_s(stringBuffer, _countof(stringBuffer), L"\tImports: %u", totalImports);
StatusBar.SetText(PART_COUNT, stringBuffer);
if(invalidImports > 0)
{
StatusBar.SetIcon(PART_INVALID, hIconError);
}
else
{
StatusBar.SetIcon(PART_INVALID, hIconCheck);
}
swprintf_s(stringBuffer, _countof(stringBuffer), L"\tInvalid: %u", invalidImports);
StatusBar.SetText(PART_INVALID, stringBuffer);
if(selectedProcess)
{
DWORD_PTR imageBase = 0;
const WCHAR * fileName = 0;
if(ProcessAccessHelp::selectedModule)
{
imageBase = ProcessAccessHelp::selectedModule->modBaseAddr;
fileName = ProcessAccessHelp::selectedModule->getFilename();
}
else
{
imageBase = selectedProcess->imageBase;
fileName = selectedProcess->filename;
}
swprintf_s(stringBuffer, _countof(stringBuffer), L"\tImagebase: " PRINTF_DWORD_PTR_FULL, imageBase);
StatusBar.SetText(PART_IMAGEBASE, stringBuffer);
StatusBar.SetText(PART_MODULE, fileName);
StatusBar.SetTipText(PART_MODULE, fileName);
}
else
{
StatusBar.SetText(PART_IMAGEBASE, L"");
StatusBar.SetText(PART_MODULE, L"");
}
}
bool MainGui::showFileDialog(WCHAR * selectedFile, bool save, const WCHAR * defFileName, const WCHAR * filter, const WCHAR * defExtension, const WCHAR * directory)
{
OPENFILENAME ofn = {0};
// WTL doesn't support new explorer styles on Vista and up
// This is because it uses a custom hook, we could remove it or derive
// from CFileDialog but this solution is easier and allows more control anyway (e.g. initial dir)
if(defFileName)
{
wcscpy_s(selectedFile, MAX_PATH, defFileName);
}
else
{
selectedFile[0] = L'\0';
}
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFilter = filter;
ofn.lpstrDefExt = defExtension; // only first 3 chars are used, no dots!
ofn.lpstrFile = selectedFile;
ofn.lpstrInitialDir = directory;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
/*
*OFN_EXPLORER is automatically used, it only has to be specified
*if using a custom hook
*OFN_LONGNAMES is automatically used by explorer-style dialogs
*/
if(save)
ofn.Flags |= OFN_OVERWRITEPROMPT;
else
ofn.Flags |= OFN_FILEMUSTEXIST;
if(save)
return 0 != GetSaveFileName(&ofn);
else
return 0 != GetOpenFileName(&ofn);
}
void MainGui::setIconAndDialogCaption()
{
SetIcon(hIcon, TRUE);
SetIcon(hIcon, FALSE);
SetWindowText(APPNAME L" " ARCHITECTURE L" " APPVERSION);
}
void MainGui::pickDllActionHandler()
{
if(!selectedProcess)
return;
PickDllGui dlgPickDll(ProcessAccessHelp::moduleList);
if(dlgPickDll.DoModal())
{
//get selected module
ProcessAccessHelp::selectedModule = dlgPickDll.getSelectedModule();
ProcessAccessHelp::targetImageBase = ProcessAccessHelp::selectedModule->modBaseAddr;
Scylla::windowLog.log(L"->>> Module %s selected.", ProcessAccessHelp::selectedModule->getFilename());
Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", ProcessAccessHelp::selectedModule->modBaseAddr, ProcessAccessHelp::selectedModule->modBaseSize);
}
else
{
ProcessAccessHelp::selectedModule = 0;
}
updateStatusBar();
}
void MainGui::pickApiActionHandler(CTreeItem item)
{
if(!importsHandling.isImport(item))
return;
// TODO: new node when user picked an API from another DLL?
PickApiGui dlgPickApi(ProcessAccessHelp::moduleList);
if(dlgPickApi.DoModal())
{
const ApiInfo* api = dlgPickApi.getSelectedApi();
if(api && api->module)
{
importsHandling.setImport(item, api->module->getFilename(), api->name, api->ordinal, api->hint, true, api->isForwarded);
}
}
updateStatusBar();
}
void MainGui::startDisassemblerGui(CTreeItem selectedTreeNode)
{
if(!selectedProcess)
return;
DWORD_PTR address = importsHandling.getApiAddressByNode(selectedTreeNode);
if (address)
{
BYTE test;
if(!ProcessAccessHelp::readMemoryFromProcess(address, sizeof(test), &test))
{
swprintf_s(stringBuffer, _countof(stringBuffer), L"Can't read memory at " PRINTF_DWORD_PTR_FULL, address);
MessageBox(stringBuffer, L"Failure", MB_ICONERROR);
}
else
{
DisassemblerGui dlgDisassembler(address);
dlgDisassembler.DoModal();
}
}
}
void MainGui::processSelectedActionHandler(int index)
{
std::vector<Process>& processList = Scylla::processLister.getProcessList();
Process &process = processList.at(index);
selectedProcess = 0;
clearImportsActionHandler();
Scylla::windowLog.log(L"Analyzing %s", process.fullPath);
if (ProcessAccessHelp::hProcess != 0)
{
ProcessAccessHelp::closeProcessHandle();
apiReader.clearAll();
}
if (!ProcessAccessHelp::openProcessHandle(process.PID))
{
enableDialogControls(FALSE);
Scylla::windowLog.log(L"Error: Cannot open process handle.");
updateStatusBar();
return;
}
ProcessAccessHelp::getProcessModules(process.PID, ProcessAccessHelp::moduleList);
apiReader.readApisFromModuleList();
Scylla::windowLog.log(L"Loading modules done.");
//TODO improve
ProcessAccessHelp::selectedModule = 0;
ProcessAccessHelp::targetSizeOfImage = process.imageSize;
ProcessAccessHelp::targetImageBase = process.imageBase;
ProcessAccessHelp::getSizeOfImageCurrentProcess();
process.imageSize = (DWORD)ProcessAccessHelp::targetSizeOfImage;
Scylla::windowLog.log(L"Imagebase: " PRINTF_DWORD_PTR_FULL L" Size: %08X", process.imageBase, process.imageSize);
process.entryPoint = ProcessAccessHelp::getEntryPointFromFile(process.fullPath);
EditOEPAddress.SetValue(process.entryPoint + process.imageBase);
selectedProcess = &process;
enableDialogControls(TRUE);
updateStatusBar();
}
void MainGui::fillProcessListComboBox(CComboBox& hCombo)
{
hCombo.ResetContent();
std::vector<Process>& processList = Scylla::processLister.getProcessListSnapshot();
for (size_t i = 0; i < processList.size(); i++)
{
swprintf_s(stringBuffer, _countof(stringBuffer), L"0x%04X - %s - %s", processList[i].PID, processList[i].filename, processList[i].fullPath);
hCombo.AddString(stringBuffer);
}
}
/*
void MainGui::addTextToOutputLog(const WCHAR * text)
{
if (m_hWnd)
{
ListLog.SetCurSel(ListLog.AddString(text));
}
}
*/
void MainGui::clearOutputLog()
{
if (m_hWnd)
{
ListLog.ResetContent();
}
}
bool MainGui::saveLogToFile(const WCHAR * file)
{
const BYTE BOM[] = {0xFF, 0xFE}; // UTF-16 little-endian
const WCHAR newLine[] = L"\r\n";
bool success = true;
HANDLE hFile = CreateFile(file, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(hFile != INVALID_HANDLE_VALUE)
{
ProcessAccessHelp::writeMemoryToFileEnd(hFile, sizeof(BOM), BOM);
WCHAR * buffer = 0;
size_t bufsize = 0;
for(int i = 0; i < ListLog.GetCount(); i++)
{
size_t size = ListLog.GetTextLen(i);
size += _countof(newLine)-1;
if(size+1 > bufsize)
{
bufsize = size+1;
delete[] buffer;
try
{
buffer = new WCHAR[bufsize];
}
catch(std::bad_alloc&)
{
buffer = 0;
success = false;
break;
}
}
ListLog.GetText(i, buffer);
wcscat_s(buffer, bufsize, newLine);
ProcessAccessHelp::writeMemoryToFileEnd(hFile, (DWORD)(size * sizeof(WCHAR)), buffer);
}
delete[] buffer;
CloseHandle(hFile);
}
return success;
}
void MainGui::showInvalidImportsActionHandler()
{
importsHandling.selectImports(true, false);
GotoDlgCtrl(TreeImports);
}
void MainGui::showSuspectImportsActionHandler()
{
importsHandling.selectImports(false, true);
GotoDlgCtrl(TreeImports);
}
void MainGui::deleteSelectedImportsActionHandler()
{
CTreeItem selected = TreeImports.GetFirstSelectedItem();
while(!selected.IsNull())
{
if(importsHandling.isModule(selected))
{
importsHandling.cutModule(selected);
}
else
{
importsHandling.cutImport(selected);
}
selected = TreeImports.GetNextSelectedItem(selected);
}
updateStatusBar();
}
void MainGui::invalidateSelectedImportsActionHandler()
{
CTreeItem selected = TreeImports.GetFirstSelectedItem();
while(!selected.IsNull())
{
if(importsHandling.isImport(selected))
{
importsHandling.invalidateImport(selected);
}
selected = TreeImports.GetNextSelectedItem(selected);
}
updateStatusBar();
}
void MainGui::loadTreeActionHandler()
{
if(!selectedProcess)
return;
WCHAR selectedFilePath[MAX_PATH];
TreeImportExport treeIO;
DWORD_PTR addrOEP = 0;
DWORD_PTR addrIAT = 0;
DWORD sizeIAT = 0;
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer))
{
if(!treeIO.importTreeList(selectedFilePath, importsHandling.moduleList, &addrOEP, &addrIAT, &sizeIAT))
{
Scylla::windowLog.log(L"Loading tree file failed %s", selectedFilePath);
MessageBox(L"Loading tree file failed.", L"Failure", MB_ICONERROR);
}
else
{
EditOEPAddress.SetValue(addrOEP);
EditIATAddress.SetValue(addrIAT);
EditIATSize.SetValue(sizeIAT);
importsHandling.displayAllImports();
updateStatusBar();
Scylla::windowLog.log(L"Loaded tree file %s", selectedFilePath);
Scylla::windowLog.log(L"-> OEP: " PRINTF_DWORD_PTR_FULL, addrOEP);
Scylla::windowLog.log(L"-> IAT: " PRINTF_DWORD_PTR_FULL L" Size: " PRINTF_DWORD_PTR, addrIAT, sizeIAT);
}
}
}
void MainGui::saveTreeActionHandler()
{
if(!selectedProcess)
return;
WCHAR selectedFilePath[MAX_PATH];
TreeImportExport treeIO;
DWORD_PTR addrOEP;
DWORD_PTR addrIAT;
DWORD sizeIAT;
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer))
{
addrOEP = EditOEPAddress.GetValue();
addrIAT = EditIATAddress.GetValue();
sizeIAT = EditIATSize.GetValue();
if(!treeIO.exportTreeList(selectedFilePath, importsHandling.moduleList, selectedProcess, addrOEP, addrIAT, sizeIAT))
{
Scylla::windowLog.log(L"Saving tree file failed %s", selectedFilePath);
MessageBox(L"Saving tree file failed.", L"Failure", MB_ICONERROR);
}
else
{
Scylla::windowLog.log(L"Saved tree file %s", selectedFilePath);
}
}
}
void MainGui::iatAutosearchActionHandler()
{
DWORD_PTR searchAddress = 0;
DWORD_PTR addressIAT = 0;
DWORD sizeIAT = 0;
IATSearch iatSearch;
if(!selectedProcess)
return;
if(EditOEPAddress.GetWindowTextLength() > 0)
{
searchAddress = EditOEPAddress.GetValue();
if (searchAddress)
{
if (iatSearch.searchImportAddressTableInProcess(searchAddress, &addressIAT, &sizeIAT))
{
Scylla::windowLog.log(L"IAT found at VA " PRINTF_DWORD_PTR_FULL L" RVA " PRINTF_DWORD_PTR_FULL L" Size 0x%04X (%d)", addressIAT, addressIAT - ProcessAccessHelp::targetImageBase, sizeIAT, sizeIAT);
EditIATAddress.SetValue(addressIAT);
EditIATSize.SetValue(sizeIAT);
swprintf_s(stringBuffer, _countof(stringBuffer), L"IAT found:\r\n\r\nStart: " PRINTF_DWORD_PTR_FULL L"\r\nSize: 0x%04X (%d) ", addressIAT, sizeIAT, sizeIAT);
MessageBox(stringBuffer, L"IAT found", MB_ICONINFORMATION);
}
else
{
Scylla::windowLog.log(L"IAT not found at OEP " PRINTF_DWORD_PTR_FULL L"!", searchAddress);
}
}
}
}
void MainGui::getImportsActionHandler()
{
if(!selectedProcess)
return;
DWORD_PTR addressIAT = EditIATAddress.GetValue();
DWORD sizeIAT = EditIATSize.GetValue();
if (addressIAT && sizeIAT)
{
apiReader.readAndParseIAT(addressIAT, sizeIAT, importsHandling.moduleList);
importsHandling.displayAllImports();
updateStatusBar();
}
}
void MainGui::SetupImportsMenuItems(CTreeItem item)
{
bool isItem, isImport = false;
isItem = !item.IsNull();
if(isItem)
{
isImport = importsHandling.isImport(item);
}
CMenuHandle hSub = hMenuImports.GetSubMenu(0);
UINT itemOnly = isItem ? MF_ENABLED : MF_GRAYED;
UINT importOnly = isImport ? MF_ENABLED : MF_GRAYED;
hSub.EnableMenuItem(ID__INVALIDATE, itemOnly);
hSub.EnableMenuItem(ID__DISASSEMBLE, importOnly);
hSub.EnableMenuItem(ID__CUTTHUNK, importOnly);
hSub.EnableMenuItem(ID__DELETETREENODE, itemOnly);
}
void MainGui::DisplayContextMenuImports(CWindow hwnd, CPoint pt)
{
if(TreeImports.GetCount() < 1)
return;
CTreeItem over, parent;
if(pt.x == -1 && pt.y == -1) // invoked by keyboard
{
CRect pos;
over = TreeImports.GetFocusItem();
if(over)
{
over.EnsureVisible();
over.GetRect(&pos, TRUE);
TreeImports.ClientToScreen(&pos);
}
else
{
TreeImports.GetWindowRect(&pos);
}
pt = pos.TopLeft();
}
else
{
// Get item under cursor
over = findTreeItem(pt, true);
}
SetupImportsMenuItems(over);
CMenuHandle hSub = hMenuImports.GetSubMenu(0);
BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd);
if (menuItem)
{
if ((menuItem >= PLUGIN_MENU_BASE_ID) && (menuItem <= (int)(Scylla::plugins.getScyllaPluginList().size() + Scylla::plugins.getImprecPluginList().size() + PLUGIN_MENU_BASE_ID)))
{
//wsprintf(stringBuffer, L"%d %s\n",menuItem,pluginList[menuItem - PLUGIN_MENU_BASE_ID].pluginName);
//MessageBox(stringBuffer, L"plugin selection");
pluginActionHandler(menuItem);
return;
}
switch (menuItem)
{
case ID__INVALIDATE:
if(importsHandling.isModule(over))
importsHandling.invalidateModule(over);
else
importsHandling.invalidateImport(over);
break;
case ID__DISASSEMBLE:
startDisassemblerGui(over);
break;
case ID__EXPANDALLNODES:
importsHandling.expandAllTreeNodes();
break;
case ID__COLLAPSEALLNODES:
importsHandling.collapseAllTreeNodes();
break;
case ID__CUTTHUNK:
importsHandling.cutImport(over);
break;
case ID__DELETETREENODE:
importsHandling.cutModule(importsHandling.isImport(over) ? over.GetParent() : over);
break;
}
}
updateStatusBar();
}
void MainGui::DisplayContextMenuLog(CWindow hwnd, CPoint pt)
{
if(pt.x == -1 && pt.y == -1) // invoked by keyboard
{
CRect pos;
ListLog.GetWindowRect(&pos);
pt = pos.TopLeft();
}
CMenuHandle hSub = hMenuLog.GetSubMenu(0);
BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, hwnd);
if (menuItem)
{
switch (menuItem)
{
case ID__SAVE:
WCHAR selectedFilePath[MAX_PATH];
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, NULL, filterTxt, L"txt", stringBuffer))
{
saveLogToFile(selectedFilePath);
}
break;
case ID__CLEAR:
clearOutputLog();
break;
}
}
}
void MainGui::appendPluginListToMenu(CMenuHandle hMenu)
{
std::vector<Plugin> &scyllaPluginList = Scylla::plugins.getScyllaPluginList();
std::vector<Plugin> &imprecPluginList = Scylla::plugins.getImprecPluginList();
if (scyllaPluginList.size() > 0)
{
CMenuHandle newMenu;
newMenu.CreatePopupMenu();
for (size_t i = 0; i < scyllaPluginList.size(); i++)
{
newMenu.AppendMenu(MF_STRING, i + PLUGIN_MENU_BASE_ID, scyllaPluginList[i].pluginName);
}
hMenu.AppendMenu(MF_MENUBARBREAK);
hMenu.AppendMenu(MF_POPUP, newMenu, L"Scylla Plugins");
}
if (imprecPluginList.size() > 0)
{
CMenuHandle newMenu;
newMenu.CreatePopupMenu();
for (size_t i = 0; i < imprecPluginList.size(); i++)
{
newMenu.AppendMenu(MF_STRING, scyllaPluginList.size() + i + PLUGIN_MENU_BASE_ID, imprecPluginList[i].pluginName);
}
hMenu.AppendMenu(MF_MENUBARBREAK);
hMenu.AppendMenu(MF_POPUP, newMenu, L"ImpREC Plugins");
}
}
void MainGui::dumpActionHandler()
{
if(!selectedProcess)
return;
WCHAR selectedFilePath[MAX_PATH];
const WCHAR * fileFilter;
const WCHAR * defExtension;
PeDump peDump;
if (ProcessAccessHelp::selectedModule)
{
fileFilter = filterDll;
defExtension = L"dll";
}
else
{
fileFilter = filterExe;
defExtension = L"exe";
}
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer))
{
if (ProcessAccessHelp::selectedModule)
{
//dump DLL
peDump.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr;
peDump.sizeOfImage = ProcessAccessHelp::selectedModule->modBaseSize;
//get it from gui
peDump.entryPoint = EditOEPAddress.GetValue();
wcscpy_s(peDump.fullpath, _countof(peDump.fullpath), ProcessAccessHelp::selectedModule->fullPath);
}
else
{
peDump.imageBase = ProcessAccessHelp::targetImageBase;
peDump.sizeOfImage = (DWORD)ProcessAccessHelp::targetSizeOfImage;
//get it from gui
peDump.entryPoint = EditOEPAddress.GetValue();
wcscpy_s(peDump.fullpath, _countof(peDump.fullpath), selectedProcess->fullPath);
}
- peDump.useHeaderFromDisk = Scylla::config.getConfigObject(USE_PE_HEADER_FROM_DISK)->isTrue();
+ peDump.useHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue();
if (peDump.dumpCompleteProcessToDisk(selectedFilePath))
{
Scylla::windowLog.log(L"Dump success %s", selectedFilePath);
}
else
{
Scylla::windowLog.log(L"Error: Cannot dump image.");
MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR);
}
}
}
void MainGui::peRebuildActionHandler()
{
DWORD newSize = 0;
WCHAR selectedFilePath[MAX_PATH];
PeRebuild peRebuild;
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer))
{
- if (Scylla::config.getConfigObject(CREATE_BACKUP)->isTrue())
+ if (Scylla::config[CREATE_BACKUP].isTrue())
{
if (!ProcessAccessHelp::createBackupFile(selectedFilePath))
{
Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath);
}
}
LONGLONG fileSize = ProcessAccessHelp::getFileSize(selectedFilePath);
LPVOID mapped = peRebuild.createFileMappingViewFull(selectedFilePath);
newSize = peRebuild.realignPE(mapped, (DWORD)fileSize);
peRebuild.closeAllMappingHandles();
if (newSize < 10)
{
Scylla::windowLog.log(L"Rebuild failed %s", selectedFilePath);
MessageBox(L"Rebuild failed.", L"Failure", MB_ICONERROR);
}
else
{
peRebuild.truncateFile(selectedFilePath, newSize);
Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath);
Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", (DWORD)fileSize, newSize, (DWORD)((newSize * 100) / (DWORD)fileSize) );
}
}
}
void MainGui::dumpFixActionHandler()
{
if(!selectedProcess)
return;
if (TreeImports.GetCount() < 2)
{
Scylla::windowLog.log(L"Nothing to rebuild");
return;
}
WCHAR newFilePath[MAX_PATH];
WCHAR selectedFilePath[MAX_PATH];
const WCHAR * fileFilter;
if (ProcessAccessHelp::selectedModule)
{
fileFilter = filterDll;
}
else
{
fileFilter = filterExe;
}
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer))
{
wcscpy_s(newFilePath,_countof(newFilePath),selectedFilePath);
const WCHAR * extension = 0;
WCHAR* dot = wcsrchr(newFilePath, L'.');
if (dot)
{
*dot = L'\0';
extension = selectedFilePath + (dot - newFilePath); //wcsrchr(selectedFilePath, L'.');
}
wcscat_s(newFilePath, _countof(newFilePath), L"_SCY");
if(extension)
{
wcscat_s(newFilePath, _countof(newFilePath), extension);
}
ImportRebuild importRebuild;
if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList))
{
Scylla::windowLog.log(L"Import Rebuild success %s", newFilePath);
}
else
{
Scylla::windowLog.log(L"Import Rebuild failed %s", selectedFilePath);
MessageBox(L"Import Rebuild failed", L"Failure", MB_ICONERROR);
}
}
}
void MainGui::enableDialogControls(BOOL value)
{
BOOL valButton = value ? TRUE : FALSE;
GetDlgItem(IDC_BTN_PICKDLL).EnableWindow(valButton);
GetDlgItem(IDC_BTN_DUMP).EnableWindow(valButton);
GetDlgItem(IDC_BTN_FIXDUMP).EnableWindow(valButton);
GetDlgItem(IDC_BTN_IATAUTOSEARCH).EnableWindow(valButton);
GetDlgItem(IDC_BTN_GETIMPORTS).EnableWindow(valButton);
GetDlgItem(IDC_BTN_SUSPECTIMPORTS).EnableWindow(valButton);
GetDlgItem(IDC_BTN_INVALIDIMPORTS).EnableWindow(valButton);
GetDlgItem(IDC_BTN_CLEARIMPORTS).EnableWindow(valButton);
CMenuHandle menu = GetMenu();
UINT valMenu = value ? MF_ENABLED : MF_GRAYED;
menu.EnableMenuItem(ID_FILE_DUMP, valMenu);
menu.EnableMenuItem(ID_FILE_FIXDUMP, valMenu);
menu.EnableMenuItem(ID_IMPORTS_INVALIDATESELECTED, valMenu);
menu.EnableMenuItem(ID_IMPORTS_CUTSELECTED, valMenu);
menu.EnableMenuItem(ID_IMPORTS_SAVETREE, valMenu);
menu.EnableMenuItem(ID_IMPORTS_LOADTREE, valMenu);
menu.EnableMenuItem(ID_MISC_DLLINJECTION, valMenu);
menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetScylla, MF_BYPOSITION | valMenu);
menu.GetSubMenu(MenuImportsOffsetTrace).EnableMenuItem(MenuImportsTraceOffsetImpRec, MF_BYPOSITION | valMenu);
//not yet implemented
GetDlgItem(IDC_BTN_AUTOTRACE).EnableWindow(FALSE);
menu.EnableMenuItem(ID_TRACE_AUTOTRACE, MF_GRAYED);
}
CTreeItem MainGui::findTreeItem(CPoint pt, bool screenCoordinates)
{
if(screenCoordinates)
{
TreeImports.ScreenToClient(&pt);
}
UINT flags;
CTreeItem over = TreeImports.HitTest(pt, &flags);
if(over)
{
if(!(flags & TVHT_ONITEM))
{
over.m_hTreeItem = NULL;
}
}
return over;
}
void MainGui::showAboutDialog()
{
AboutGui dlgAbout;
dlgAbout.DoModal();
}
void MainGui::dllInjectActionHandler()
{
if(!selectedProcess)
return;
WCHAR selectedFilePath[MAX_PATH];
HMODULE hMod = 0;
DllInjection dllInjection;
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if (showFileDialog(selectedFilePath, false, NULL, filterDll, NULL, stringBuffer))
{
hMod = dllInjection.dllInjection(ProcessAccessHelp::hProcess, selectedFilePath);
- if (hMod && Scylla::config.getConfigObject(DLL_INJECTION_AUTO_UNLOAD)->isTrue())
+ if (hMod && Scylla::config[DLL_INJECTION_AUTO_UNLOAD].isTrue())
{
if (!dllInjection.unloadDllInProcess(ProcessAccessHelp::hProcess, hMod))
{
Scylla::windowLog.log(L"DLL unloading failed, target %s", selectedFilePath);
}
}
if (hMod)
{
Scylla::windowLog.log(L"DLL Injection was successful, target %s", selectedFilePath);
}
else
{
Scylla::windowLog.log(L"DLL Injection failed, target %s", selectedFilePath);
}
}
}
void MainGui::optionsActionHandler()
{
OptionsGui dlgOptions;
dlgOptions.DoModal();
}
void MainGui::clearImportsActionHandler()
{
importsHandling.clearAllImports();
updateStatusBar();
}
void MainGui::pluginActionHandler( int menuItem )
{
if(!selectedProcess)
return;
DllInjectionPlugin dllInjectionPlugin;
std::vector<Plugin> &scyllaPluginList = Scylla::plugins.getScyllaPluginList();
std::vector<Plugin> &imprecPluginList = Scylla::plugins.getImprecPluginList();
menuItem -= PLUGIN_MENU_BASE_ID;
dllInjectionPlugin.hProcess = ProcessAccessHelp::hProcess;
dllInjectionPlugin.apiReader = &apiReader;
if (menuItem < (int)scyllaPluginList.size())
{
//scylla plugin
dllInjectionPlugin.injectPlugin(scyllaPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize);
}
else
{
#ifndef _WIN64
menuItem -= (int)scyllaPluginList.size();
//imprec plugin
dllInjectionPlugin.injectImprecPlugin(imprecPluginList[menuItem], importsHandling.moduleList,selectedProcess->imageBase, selectedProcess->imageSize);
#endif
}
importsHandling.scanAndFixModuleList();
importsHandling.displayAllImports();
updateStatusBar();
}
bool MainGui::getCurrentModulePath(TCHAR * buffer, size_t bufferSize)
{
if(!selectedProcess)
return false;
if(ProcessAccessHelp::selectedModule)
{
wcscpy_s(buffer, bufferSize, ProcessAccessHelp::selectedModule->fullPath);
}
else
{
wcscpy_s(buffer, bufferSize, selectedProcess->fullPath);
}
WCHAR * slash = wcsrchr(buffer, L'\\');
if(slash)
{
*(slash+1) = L'\0';
}
return true;
}
diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp
index f29cb36..f56795a 100644
--- a/Scylla/OptionsGui.cpp
+++ b/Scylla/OptionsGui.cpp
@@ -1,89 +1,48 @@
#include "OptionsGui.h"
#include "Scylla.h"
BOOL OptionsGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
{
loadOptions();
DoDataExchange(DDX_LOAD); // show settings
EditSectionName.LimitText(IMAGE_SIZEOF_SHORT_NAME);
CenterWindow();
return TRUE;
}
void OptionsGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl)
{
DoDataExchange(DDX_SAVE);
saveOptions();
Scylla::config.saveConfiguration();
EndDialog(0);
}
void OptionsGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl)
{
EndDialog(0);
}
-void OptionsGui::saveOptions()
+void OptionsGui::saveOptions() const
{
- std::map<Configuration, ConfigObject>::iterator mapIter;
-
- for (mapIter = Scylla::config.getConfigList().begin() ; mapIter != Scylla::config.getConfigList().end(); mapIter++)
- {
- switch(mapIter->first)
- {
- case USE_PE_HEADER_FROM_DISK:
- usePEHeaderFromDisk ? mapIter->second.setTrue() : mapIter->second.setFalse();
- break;
- case DEBUG_PRIVILEGE:
- debugPrivilege ? mapIter->second.setTrue() : mapIter->second.setFalse();
- break;
- case CREATE_BACKUP:
- createBackup ? mapIter->second.setTrue() : mapIter->second.setFalse();
- break;
- case DLL_INJECTION_AUTO_UNLOAD:
- dllInjectionAutoUnload ? mapIter->second.setTrue() : mapIter->second.setFalse();
- break;
- case UPDATE_HEADER_CHECKSUM:
- updateHeaderChecksum ? mapIter->second.setTrue() : mapIter->second.setFalse();
- break;
- case IAT_SECTION_NAME:
- wcscpy_s(mapIter->second.valueString, _countof(mapIter->second.valueString), iatSectionName);
- break;
- }
- }
+ Scylla::config[USE_PE_HEADER_FROM_DISK].setBool(usePEHeaderFromDisk);
+ Scylla::config[DEBUG_PRIVILEGE].setBool(debugPrivilege);
+ Scylla::config[CREATE_BACKUP].setBool(createBackup);
+ Scylla::config[DLL_INJECTION_AUTO_UNLOAD].setBool(dllInjectionAutoUnload);
+ Scylla::config[UPDATE_HEADER_CHECKSUM].setBool(updateHeaderChecksum);
+ Scylla::config[IAT_SECTION_NAME].setString(iatSectionName);
}
void OptionsGui::loadOptions()
{
- std::map<Configuration, ConfigObject>::iterator mapIter;
-
- for (mapIter = Scylla::config.getConfigList().begin() ; mapIter != Scylla::config.getConfigList().end(); mapIter++)
- {
- switch(mapIter->first)
- {
- case USE_PE_HEADER_FROM_DISK:
- usePEHeaderFromDisk = mapIter->second.isTrue();
- break;
- case DEBUG_PRIVILEGE:
- debugPrivilege = mapIter->second.isTrue();
- break;
- case CREATE_BACKUP:
- createBackup = mapIter->second.isTrue();
- break;
- case DLL_INJECTION_AUTO_UNLOAD:
- dllInjectionAutoUnload = mapIter->second.isTrue();
- break;
- case UPDATE_HEADER_CHECKSUM:
- updateHeaderChecksum = mapIter->second.isTrue();
- break;
- case IAT_SECTION_NAME:
- wcsncpy_s(iatSectionName, _countof(iatSectionName), mapIter->second.valueString, _countof(iatSectionName)-1);
- iatSectionName[_countof(iatSectionName)-1] = L'\0';
- break;
- }
- }
+ usePEHeaderFromDisk = Scylla::config[USE_PE_HEADER_FROM_DISK].getBool();
+ debugPrivilege = Scylla::config[DEBUG_PRIVILEGE].getBool();
+ createBackup = Scylla::config[CREATE_BACKUP].getBool();
+ dllInjectionAutoUnload = Scylla::config[DLL_INJECTION_AUTO_UNLOAD].getBool();
+ updateHeaderChecksum = Scylla::config[UPDATE_HEADER_CHECKSUM].getBool();
+ wcsncpy_s(iatSectionName, Scylla::config[IAT_SECTION_NAME].getString(), _countof(iatSectionName)-1);
}
diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h
index 422bfc2..8d3fd95 100644
--- a/Scylla/OptionsGui.h
+++ b/Scylla/OptionsGui.h
@@ -1,63 +1,63 @@
#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 <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
class OptionsGui : public CDialogImpl<OptionsGui>, public CWinDataExchange<OptionsGui>
{
public:
enum { IDD = IDD_DLG_OPTIONS };
BEGIN_DDX_MAP(OptionsGui)
DDX_CONTROL_HANDLE(IDC_OPTIONS_SECTIONNAME, EditSectionName)
DDX_TEXT(IDC_OPTIONS_SECTIONNAME, iatSectionName)
DDX_CHECK(IDC_CHECK_HEADER_CHECKSUM, updateHeaderChecksum)
DDX_CHECK(IDC_CHECK_CREATE_BACKUP, createBackup)
DDX_CHECK(IDC_CHECK_UNLOAD_DLL, dllInjectionAutoUnload)
DDX_CHECK(IDC_CHECK_PE_HEADER_FROM_DISK, usePEHeaderFromDisk)
DDX_CHECK(IDC_CHECK_DEBUG_PRIVILEGES, debugPrivilege)
END_DDX_MAP()
BEGIN_MSG_MAP(OptionsGui)
MSG_WM_INITDIALOG(OnInitDialog)
COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_BTN_OPTIONS_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
END_MSG_MAP()
protected:
// Settings (filled by DDX)
WCHAR iatSectionName[IMAGE_SIZEOF_SHORT_NAME+1];
bool updateHeaderChecksum;
bool createBackup;
bool dllInjectionAutoUnload;
bool usePEHeaderFromDisk;
bool debugPrivilege;
// Controls
CEdit EditSectionName;
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
// Gui helpers
- void saveOptions();
+ void saveOptions() const;
void loadOptions();
};
diff --git a/Scylla/PeRebuild.cpp b/Scylla/PeRebuild.cpp
index a8106af..0d50ec6 100644
--- a/Scylla/PeRebuild.cpp
+++ b/Scylla/PeRebuild.cpp
@@ -1,736 +1,736 @@
#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.getConfigObject(UPDATE_HEADER_CHECKSUM)->isTrue())
+ 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/Scylla.vcxproj b/Scylla/Scylla.vcxproj
index c38dc6e..0848e32 100644
--- a/Scylla/Scylla.vcxproj
+++ b/Scylla/Scylla.vcxproj
@@ -1,233 +1,235 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{710434C9-FC4B-4F1D-B318-E10ADC78499F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Scylla</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v100</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' </AdditionalManifestDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' </AdditionalManifestDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MinimalRebuild>true</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' </AdditionalManifestDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>$(SolutionDir)diStorm\include;$(SolutionDir)tinyxml;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MinimalRebuild>true</MinimalRebuild>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>$(SolutionDir)$(Platform)\$(Configuration)\diStorm.lib;$(SolutionDir)$(Platform)\$(Configuration)\tinyxml.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalManifestDependencies>type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' </AdditionalManifestDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AboutGui.cpp" />
<ClCompile Include="ApiReader.cpp" />
<ClCompile Include="Architecture.cpp" />
+ <ClCompile Include="Configuration.cpp" />
<ClCompile Include="ConfigurationHolder.cpp" />
<ClCompile Include="DisassemblerGui.cpp" />
<ClCompile Include="DllInjection.cpp" />
<ClCompile Include="DllInjectionPlugin.cpp" />
<ClCompile Include="IATSearch.cpp" />
<ClCompile Include="ImportRebuild.cpp" />
<ClCompile Include="ImportsHandling.cpp" />
<ClCompile Include="Logger.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MainGui.cpp" />
<ClCompile Include="NativeWinApi.cpp" />
<ClCompile Include="OptionsGui.cpp" />
<ClCompile Include="PeDump.cpp" />
<ClCompile Include="PeRebuild.cpp" />
<ClCompile Include="PickApiGui.cpp" />
<ClCompile Include="PickDllGui.cpp" />
<ClCompile Include="PluginLoader.cpp" />
<ClCompile Include="ProcessAccessHelp.cpp" />
<ClCompile Include="ProcessLister.cpp" />
<ClCompile Include="Scylla.cpp" />
<ClCompile Include="SystemInformation.cpp" />
<ClCompile Include="TreeImportExport.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AboutGui.h" />
<ClInclude Include="ApiReader.h" />
<ClInclude Include="Architecture.h" />
+ <ClInclude Include="Configuration.h" />
<ClInclude Include="ConfigurationHolder.h" />
<ClInclude Include="definitions.h" />
<ClInclude Include="DisassemblerGui.h" />
<ClInclude Include="DllInjection.h" />
<ClInclude Include="DllInjectionPlugin.h" />
<ClInclude Include="hexedit.h" />
<ClInclude Include="IATSearch.h" />
<ClInclude Include="ImportRebuild.h" />
<ClInclude Include="ImportsHandling.h" />
<ClInclude Include="Logger.h" />
<ClInclude Include="MainGui.h" />
<ClInclude Include="multitree.h" />
<ClInclude Include="NativeWinApi.h" />
<ClInclude Include="OptionsGui.h" />
<ClInclude Include="PeDump.h" />
<ClInclude Include="PeRebuild.h" />
<ClInclude Include="PickApiGui.h" />
<ClInclude Include="PickDllGui.h" />
<ClInclude Include="PluginLoader.h" />
<ClInclude Include="ProcessAccessHelp.h" />
<ClInclude Include="ProcessLister.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Scylla.h" />
<ClInclude Include="SystemInformation.h" />
<ClInclude Include="Thunks.h" />
<ClInclude Include="TreeImportExport.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="MainGui.rc" />
</ItemGroup>
<ItemGroup>
<None Include="check.ico" />
<None Include="error.ico" />
<None Include="scylla.ico" />
<None Include="warning.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties RESOURCE_FILE="MainGui.rc" />
</VisualStudio>
</ProjectExtensions>
</Project>
\ No newline at end of file
diff --git a/Scylla/Scylla.vcxproj.filters b/Scylla/Scylla.vcxproj.filters
index b5919e2..2837676 100644
--- a/Scylla/Scylla.vcxproj.filters
+++ b/Scylla/Scylla.vcxproj.filters
@@ -1,208 +1,214 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Headerdateien\GUI">
<UniqueIdentifier>{e037d0d5-35ad-4034-83db-746a56a4fee7}</UniqueIdentifier>
</Filter>
<Filter Include="Quelldateien\GUI">
<UniqueIdentifier>{6f76186f-b79c-41e2-8939-05d9de028aad}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="MainGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="Logger.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="ProcessLister.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="PickDllGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="ImportsHandling.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="ApiReader.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="IATSearch.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="ProcessAccessHelp.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="ImportRebuild.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="PeDump.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="PeRebuild.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="DllInjection.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="DllInjectionPlugin.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="PluginLoader.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="ConfigurationHolder.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="DisassemblerGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="NativeWinApi.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="SystemInformation.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="AboutGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="OptionsGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="PickApiGui.cpp">
<Filter>Quelldateien\GUI</Filter>
</ClCompile>
<ClCompile Include="TreeImportExport.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="Scylla.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="Architecture.cpp">
<Filter>Quelldateien</Filter>
</ClCompile>
+ <ClCompile Include="Configuration.cpp">
+ <Filter>Quelldateien</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="MainGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="Logger.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="ProcessLister.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="PickDllGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="ImportsHandling.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="ApiReader.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="IATSearch.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="ProcessAccessHelp.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="Thunks.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="PeRebuild.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="PeDump.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="ImportRebuild.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="ConfigurationHolder.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="DllInjectionPlugin.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="DllInjection.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="PluginLoader.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="definitions.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="DisassemblerGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="NativeWinApi.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="SystemInformation.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="AboutGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="OptionsGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="PickApiGui.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="multitree.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="TreeImportExport.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="hexedit.h">
<Filter>Headerdateien\GUI</Filter>
</ClInclude>
<ClInclude Include="Scylla.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="Architecture.h">
<Filter>Headerdateien</Filter>
</ClInclude>
+ <ClInclude Include="Configuration.h">
+ <Filter>Headerdateien</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="MainGui.rc">
<Filter>Ressourcendateien</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="scylla.ico">
<Filter>Ressourcendateien</Filter>
</None>
<None Include="check.ico">
<Filter>Ressourcendateien</Filter>
</None>
<None Include="error.ico">
<Filter>Ressourcendateien</Filter>
</None>
<None Include="warning.ico">
<Filter>Ressourcendateien</Filter>
</None>
</ItemGroup>
</Project>
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, May 27, 7:29 AM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
3d/be/739b80288219b1f8fe29bf6488c6
Attached To
rSCY Scylla
Event Timeline
Log In to Comment