Page Menu
Home
desp's stash
Search
Configure Global Search
Log In
Files
F352095
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
155 KB
Subscribers
None
View Options
diff --git a/README.md b/README.md
index 1e7192a..deda214 100644
--- a/README.md
+++ b/README.md
@@ -1,106 +1,115 @@
Scylla - x64/x86 Imports Reconstruction
=======================================
ImpREC, CHimpREC, Imports Fixer... this are all great tools to rebuild an import table,
but they all have some major disadvantages, so I decided to create my own tool for this job.
Scylla's key benefits are:
- x64 and x86 support
- full unicode support (probably some russian or chinese will like this :-) )
- written in C/C++
- plugin support
- works great with Windows 7
This tool was designed to be used with Windows 7 x64, so it is recommend to use this operating system.
But it may work with XP and Vista, too.
Source code is licensed under GNU GENERAL PUBLIC LICENSE v3.0
Known Bugs
----------
### Only Windows XP x64:
Windows XP x64 has some API bugs. 100% correct imports reconstruction is impossible.
If you still want to use XP x64, here are some hints:
* EncodePointer/DecodePointer exported by kernel32.dll have both the same VA.
Scylla, CHimpREC and other tools cannot know which API is correct. You need to fix this manually.
Your fixed dump will probably run fine on XP but crash on Vista/7.
### ImpREC plugin support:
Some ImpREC Plugins don't work with Windows Vista/7 because they don't "return 1" in the DllMain function.
Keyboard Shortcuts
------------------
- CTRL + D: [D]ump
- CTRL + F: [F]ix Dump
- CTRL + R: PE [R]ebuild
- CTRL + O: L[o]ad Tree
- CTRL + S: [S]ave Tree
- CTRL + T: Auto[t]race
- CTRL + G: [G]et Imports
- CTRL + I: [I]AT Autosearch
Changelog
---------
+Version 0.6b
+
+- internal code changes
+- added option: fix iat and oep
+
+Version 0.6a
+
+- fixed buffer to small bug in dump memory
+
Version 0.6
- added dump memory regions
- added dump pe sections -> you can edit some values in the dialog
- improved dump engine with intelligent dumping
- improved pe rebuild engine -> removed yoda's code
- fixed various bugs
Version 0.5a:
- fixed memory leak
- improved IAT search
Version 0.5:
- added save/load import tree feature
- multi-select in tree view
- fixed black icons problem in tree view
- added keyboard shortcuts
- dll dump + dll dump fix now working
- added support for scattered IATs
- pre select target path in open file dialogs
- improved import resolving engine with api scoring
- api selection dialog
- minor bug fixes and improvements
Version 0.4:
- GUI code improvements
- bug fixes
- imports by ordinal
Version 0.3a:
- Improved import resolving
- fixed buffer overflow errors
Version 0.3:
- ImpREC plugin support
- minor bug fix
Version 0.2a:
- improved disassembler dialog
- improved iat search
Version 0.2:
- improved process detection
- added some options
- new options dialog
- improved source code
diff --git a/Scylla/ConfigurationHolder.cpp b/Scylla/ConfigurationHolder.cpp
index ea530f9..e555062 100644
--- a/Scylla/ConfigurationHolder.cpp
+++ b/Scylla/ConfigurationHolder.cpp
@@ -1,203 +1,204 @@
#include "ConfigurationHolder.h"
#include <shlwapi.h>
#include "Architecture.h"
const WCHAR ConfigurationHolder::CONFIG_FILE_SECTION_NAME[] = L"SCYLLA_CONFIG";
//#define DEBUG_COMMENTS
ConfigurationHolder::ConfigurationHolder(const WCHAR* fileName)
{
config[USE_PE_HEADER_FROM_DISK] = Configuration(L"USE_PE_HEADER_FROM_DISK", Configuration::Boolean);
config[DEBUG_PRIVILEGE] = Configuration(L"DEBUG_PRIVILEGE", Configuration::Boolean);
config[CREATE_BACKUP] = Configuration(L"CREATE_BACKUP", Configuration::Boolean);
config[DLL_INJECTION_AUTO_UNLOAD] = Configuration(L"DLL_INJECTION_AUTO_UNLOAD", Configuration::Boolean);
config[UPDATE_HEADER_CHECKSUM] = Configuration(L"UPDATE_HEADER_CHECKSUM", Configuration::Boolean);
config[IAT_SECTION_NAME] = Configuration(L"IAT_SECTION_NAME", Configuration::String);
config[REMOVE_DOS_HEADER_STUB] = Configuration(L"REMOVE_DOS_HEADER_STUB", Configuration::Boolean);
+ config[IAT_FIX_AND_OEP_FIX] = Configuration(L"IAT_FIX_AND_OEP_FIX", Configuration::Boolean);
buildConfigFilePath(fileName);
}
bool ConfigurationHolder::loadConfiguration()
{
std::map<ConfigOption, Configuration>::iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
Configuration& configObject = mapIter->second;
if (!loadConfig(configObject))
{
return false;
}
}
return true;
}
bool ConfigurationHolder::saveConfiguration() const
{
std::map<ConfigOption, Configuration>::const_iterator mapIter;
if (configPath[0] == '\0')
{
return false;
}
for (mapIter = config.begin() ; mapIter != config.end(); mapIter++)
{
const Configuration& configObject = mapIter->second;
if (!saveConfig(configObject))
{
return false;
}
}
return true;
}
Configuration& ConfigurationHolder::operator[](ConfigOption option)
{
return config[option];
}
const Configuration& ConfigurationHolder::operator[](ConfigOption option) const
{
static const Configuration dummy;
std::map<ConfigOption, Configuration>::const_iterator found = config.find(option);
if(found != config.end())
{
return found->second;
}
else
{
return dummy;
}
}
bool ConfigurationHolder::saveNumericToConfigFile(const Configuration & configObject, int nBase) const
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
if (nBase == 16)
{
swprintf_s(buf, PRINTF_DWORD_PTR_FULL, configObject.getNumeric());
}
else
{
swprintf_s(buf, PRINTF_INTEGER, configObject.getNumeric());
}
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), buf, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readNumericFromConfigFile(Configuration & configObject, int nBase)
{
WCHAR buf[21]; // UINT64_MAX in dec has 20 digits
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if (read > 0 && wcslen(buf) > 0)
{
#ifdef _WIN64
configObject.setNumeric(_wcstoui64(buf, NULL, nBase));
#else
configObject.setNumeric(wcstoul(buf, NULL, nBase));
#endif
return true;
}
return false;
}
bool ConfigurationHolder::saveStringToConfigFile(const Configuration & configObject) const
{
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), configObject.getString(), configPath);
return ret == TRUE;
}
bool ConfigurationHolder::readStringFromConfigFile(Configuration & configObject)
{
WCHAR buf[Configuration::CONFIG_STRING_LENGTH];
DWORD read = GetPrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), L"", buf, _countof(buf), configPath);
if(read > 0 && wcslen(buf) > 0)
{
configObject.setString(buf);
return true;
}
return false;
}
bool ConfigurationHolder::readBooleanFromConfigFile(Configuration & configObject)
{
UINT val = GetPrivateProfileInt(CONFIG_FILE_SECTION_NAME, configObject.getName(), 0, configPath);
configObject.setBool(val != 0);
return true;
}
bool ConfigurationHolder::saveBooleanToConfigFile(const Configuration & configObject) const
{
const WCHAR *boolValue = configObject.isTrue() ? L"1" : L"0";
BOOL ret = WritePrivateProfileString(CONFIG_FILE_SECTION_NAME, configObject.getName(), boolValue, configPath);
return ret == TRUE;
}
bool ConfigurationHolder::loadConfig(Configuration & configObject)
{
switch (configObject.getType())
{
case Configuration::String:
return readStringFromConfigFile(configObject);
case Configuration::Boolean:
return readBooleanFromConfigFile(configObject);
case Configuration::Decimal:
return readNumericFromConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return readNumericFromConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::saveConfig(const Configuration & configObject) const
{
switch (configObject.getType())
{
case Configuration::String:
return saveStringToConfigFile(configObject);
case Configuration::Boolean:
return saveBooleanToConfigFile(configObject);
case Configuration::Decimal:
return saveNumericToConfigFile(configObject, 10);
case Configuration::Hexadecimal:
return saveNumericToConfigFile(configObject, 16);
default:
return false;
}
}
bool ConfigurationHolder::buildConfigFilePath(const WCHAR* fileName)
{
ZeroMemory(configPath, sizeof(configPath));
if (!GetModuleFileName(0, configPath, _countof(configPath)))
{
#ifdef DEBUG_COMMENTS
Scylla::debugLog.log(L"buildConfigFilePath :: GetModuleFileName failed %d", GetLastError());
#endif
return false;
}
PathRemoveFileSpec(configPath);
PathAppend(configPath, fileName);
return true;
}
diff --git a/Scylla/ConfigurationHolder.h b/Scylla/ConfigurationHolder.h
index ab526d6..90659e1 100644
--- a/Scylla/ConfigurationHolder.h
+++ b/Scylla/ConfigurationHolder.h
@@ -1,49 +1,50 @@
#pragma once
#include <windows.h>
#include <map>
#include "Configuration.h"
enum ConfigOption
{
USE_PE_HEADER_FROM_DISK,
DEBUG_PRIVILEGE,
CREATE_BACKUP,
DLL_INJECTION_AUTO_UNLOAD,
IAT_SECTION_NAME,
UPDATE_HEADER_CHECKSUM,
- REMOVE_DOS_HEADER_STUB
+ REMOVE_DOS_HEADER_STUB,
+ IAT_FIX_AND_OEP_FIX
};
class ConfigurationHolder
{
public:
ConfigurationHolder(const WCHAR* fileName);
bool loadConfiguration();
bool saveConfiguration() const;
Configuration& operator[](ConfigOption option);
const Configuration& operator[](ConfigOption option) const;
private:
static const WCHAR CONFIG_FILE_SECTION_NAME[];
WCHAR configPath[MAX_PATH];
std::map<ConfigOption, Configuration> config;
bool buildConfigFilePath(const WCHAR* fileName);
bool readStringFromConfigFile(Configuration & configObject);
bool readBooleanFromConfigFile(Configuration & configObject);
bool readNumericFromConfigFile(Configuration & 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(Configuration & configObject);
bool saveConfig(const Configuration & configObject) const;
};
diff --git a/Scylla/DumpSectionGui.cpp b/Scylla/DumpSectionGui.cpp
index 7823f7c..2954bf2 100644
--- a/Scylla/DumpSectionGui.cpp
+++ b/Scylla/DumpSectionGui.cpp
@@ -1,394 +1,400 @@
#include "DumpSectionGui.h"
#include "Architecture.h"
#include "ProcessAccessHelp.h"
#include "PeParser.h"
bool PeSection::highlightVirtualSize()
{
//highlight big virtual sizes -> anti-dump protection
return (virtualSize > 0x2000000);
}
std::vector<PeSection> & DumpSectionGui::getSectionList()
{
return sectionList;
}
DumpSectionGui::DumpSectionGui()
{
imageBase = 0;
entryPoint = 0;
fullpath[0] = 0;
}
DumpSectionGui::~DumpSectionGui()
{
sectionList.clear();
}
BOOL DumpSectionGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
{
DoDataExchange(); // attach controls
DlgResize_Init(true, true);
addColumnsToSectionList(ListSectionSelect);
displaySectionList(ListSectionSelect);
selectOrDeselectAll();
isEditing = false;
selectedSection = 0;
CenterWindow();
return TRUE;
}
LRESULT DumpSectionGui::OnListSectionColumnClicked(NMHDR* pnmh)
{
NMLISTVIEW* list = (NMLISTVIEW*)pnmh;
int column = list->iSubItem;
if(column == prevColumn)
{
ascending = !ascending;
}
else
{
prevColumn = column;
ascending = true;
}
// lo-byte: column, hi-byte: sort-order
ListSectionSelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending));
return 0;
}
LRESULT DumpSectionGui::OnListSectionClick(NMHDR* pnmh)
{
//int index = ListSectionSelect.GetSelectionMark();
//if (index != -1)
//{
//}
return 0;
}
LRESULT DumpSectionGui::OnListDoubleClick(NMHDR* pnmh)
{
LVHITTESTINFO hti;
RECT rect, rect1, rect2;
NMITEMACTIVATE* ia = (NMITEMACTIVATE*)pnmh;
editingSubItem = ia->iSubItem;
- if (editingSubItem == COL_NAME || editingSubItem == COL_VA || editingSubItem == COL_RVA)
+ if (editingSubItem == COL_NAME || editingSubItem == COL_VA)
{
return 0;
}
hti.pt = ia->ptAction;
int clicked = ListSectionSelect.HitTest(&hti);
if(clicked != -1)
{
selectedSection = (PeSection *)ListSectionSelect.GetItemData(clicked);
}
ListSectionSelect.GetSubItemRect(ia->iItem,ia->iSubItem,LVIR_BOUNDS,&rect);
//Get the Rectange of the listControl
ListSectionSelect.GetWindowRect(&rect1);
//Get the Rectange of the Dialog
GetWindowRect(&rect2);
int x = rect1.left - rect2.left;
int y = rect1.top - rect2.top;
isEditing = true;
switch (editingSubItem)
{
case COL_VSize:
valueBeforeEditing = selectedSection->virtualSize;
break;
+ case COL_RVA:
+ valueBeforeEditing = selectedSection->rawAddress;
+ break;
case COL_RSize:
valueBeforeEditing = selectedSection->rawSize;
break;
case COL_Characteristics:
valueBeforeEditing = selectedSection->characteristics;
break;
default:
valueBeforeEditing = 0;
}
EditListControl.SetValue(valueBeforeEditing);
EditListControl.SetWindowPos(HWND_TOP,rect.left + 7, rect.top + 7, rect.right - rect.left, rect.bottom - rect.top, NULL);
EditListControl.ShowWindow(SW_SHOW);
EditListControl.SetFocus();
return 0;
}
void DumpSectionGui::OnSectionSelectAll(UINT uNotifyCode, int nID, CWindow wndCtl)
{
selectOrDeselectAll();
}
void DumpSectionGui::OnEditList(UINT uNotifyCode, int nID, CWindow wndCtl)
{
switch (uNotifyCode)
{
case EN_KILLFOCUS:
{
isEditing = false;
updateEditedItem();
EditListControl.ShowWindow(SW_HIDE);
}
break;
}
}
void DumpSectionGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl)
{
if (isEditing) //EN_KILLFOCUS not sent?
{
updateEditedItem();
}
updateCheckState();
EndDialog(1);
}
void DumpSectionGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl)
{
EndDialog(0);
}
int DumpSectionGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
const PeSection * module1 = (PeSection *)lParam1;
const PeSection * module2 = (PeSection *)lParam2;
int column = LOBYTE(lParamSort);
bool ascending = (HIBYTE(lParamSort) == TRUE);
int diff = 0;
switch(column)
{
case COL_NAME:
diff = _wcsicmp(module1->name, module2->name);
break;
case COL_VA:
diff = module1->virtualAddress < module2->virtualAddress ? -1 : 1;
break;
case COL_VSize:
diff = module1->virtualSize < module2->virtualSize ? -1 : 1;
break;
case COL_RVA:
diff = module1->rawAddress < module2->rawAddress ? -1 : 1;
break;
case COL_RSize:
diff = module1->rawSize < module2->rawSize ? -1 : 1;
break;
case COL_Characteristics:
diff = module1->characteristics < module2->characteristics ? -1 : 1;
break;
}
return ascending ? diff : -diff;
}
void DumpSectionGui::addColumnsToSectionList(CListViewCtrl& list)
{
list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES, LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES|LVS_EX_GRIDLINES);
list.InsertColumn(COL_NAME, L"Name", LVCFMT_CENTER);
list.InsertColumn(COL_VA, L"Virtual Address", LVCFMT_CENTER);
list.InsertColumn(COL_VSize, L"Virtual Size", LVCFMT_CENTER);
list.InsertColumn(COL_RVA, L"Raw Address", LVCFMT_CENTER);
list.InsertColumn(COL_RSize, L"Raw Size", LVCFMT_CENTER);
list.InsertColumn(COL_Characteristics, L"Characteristics", LVCFMT_CENTER);
}
void DumpSectionGui::displaySectionList(CListViewCtrl& list)
{
int count = 0;
WCHAR temp[20];
list.DeleteAllItems();
if (sectionList.empty())
{
getAllSectionsFromFile();
}
std::vector<PeSection>::const_iterator iter;
for( iter = sectionList.begin(); iter != sectionList.end(); iter++ , count++)
{
list.InsertItem(count, iter->name);
swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->virtualAddress);
list.SetItemText(count, COL_VA, temp);
swprintf_s(temp, L"%08X", iter->virtualSize);
list.SetItemText(count, COL_VSize, temp);
swprintf_s(temp, L"%08X", iter->rawAddress);
list.SetItemText(count, COL_RVA, temp);
swprintf_s(temp, L"%08X", iter->rawSize);
list.SetItemText(count, COL_RSize, temp);
swprintf_s(temp, L"%08X", iter->characteristics);
list.SetItemText(count, COL_Characteristics, temp);
list.SetItemData(count, (DWORD_PTR)&(*iter));
}
list.SetColumnWidth(COL_NAME, LVSCW_AUTOSIZE_USEHEADER);
list.SetColumnWidth(COL_VA, LVSCW_AUTOSIZE_USEHEADER);
list.SetColumnWidth(COL_VSize, LVSCW_AUTOSIZE_USEHEADER);
list.SetColumnWidth(COL_RVA, LVSCW_AUTOSIZE_USEHEADER);
list.SetColumnWidth(COL_RSize, LVSCW_AUTOSIZE_USEHEADER);
list.SetColumnWidth(COL_Characteristics, LVSCW_AUTOSIZE_USEHEADER);
}
LRESULT DumpSectionGui::OnNMCustomdraw(NMHDR* pnmh)
{
LRESULT pResult = 0;
unsigned int vectorIndex = 0;
LPNMLVCUSTOMDRAW lpLVCustomDraw = (LPNMLVCUSTOMDRAW)(pnmh);
switch(lpLVCustomDraw->nmcd.dwDrawStage)
{
case CDDS_ITEMPREPAINT:
case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
{
vectorIndex = (unsigned int)lpLVCustomDraw->nmcd.dwItemSpec;
if (lpLVCustomDraw->iSubItem == COL_VSize)
{
if (sectionList[vectorIndex].highlightVirtualSize())
{
lpLVCustomDraw->clrText = RGB(255,255,255); // white text
lpLVCustomDraw->clrTextBk = RGB(255,0,0); // red background
}
}
else
{
lpLVCustomDraw->clrText = CLR_DEFAULT;
lpLVCustomDraw->clrTextBk = CLR_DEFAULT;
}
}
break;
default:
break;
}
pResult |= CDRF_NOTIFYPOSTPAINT;
pResult |= CDRF_NOTIFYITEMDRAW;
pResult |= CDRF_NOTIFYSUBITEMDRAW;
return pResult;
}
void DumpSectionGui::getAllSectionsFromFile()
{
PeSection peSection;
if (sectionList.empty())
{
sectionList.reserve(3);
}
else
{
sectionList.clear();
}
PeParser peFile(fullpath);
if (peFile.isValidPeFile())
{
std::vector<PeFileSection> & listSectionHeader = peFile.getSectionHeaderList();
for (WORD i = 0; i < peFile.getNumberOfSections(); i++)
{
peFile.getSectionNameUnicode(i, peSection.name, _countof(peSection.name));
peSection.virtualAddress = imageBase + listSectionHeader[i].sectionHeader.VirtualAddress;
peSection.virtualSize = listSectionHeader[i].sectionHeader.Misc.VirtualSize;
peSection.rawAddress = listSectionHeader[i].sectionHeader.PointerToRawData;
peSection.rawSize = listSectionHeader[i].sectionHeader.SizeOfRawData;
peSection.characteristics = listSectionHeader[i].sectionHeader.Characteristics;
peSection.isDumped = true;
sectionList.push_back(peSection);
}
}
else
{
MessageBox(fullpath, L"Not a valid PE -> This should never happen", MB_ICONERROR);
}
}
void DumpSectionGui::updateEditedItem()
{
if (selectedSection)
{
DWORD newValue = EditListControl.GetValue();
if (valueBeforeEditing != newValue)
{
switch (editingSubItem)
{
case COL_VSize:
selectedSection->virtualSize = newValue;
break;
+ case COL_RVA:
+ selectedSection->rawAddress = newValue;
+ break;
case COL_RSize:
selectedSection->rawSize = newValue;
break;
case COL_Characteristics:
selectedSection->characteristics = newValue;
break;
}
displaySectionList(ListSectionSelect);
selectOrDeselectAll();
}
}
}
void DumpSectionGui::updateCheckState()
{
PeSection * pesection;
for (size_t i = 0; i < sectionList.size(); i++)
{
pesection = (PeSection *)ListSectionSelect.GetItemData((int)i);
pesection->isDumped = ListSectionSelect.GetCheckState((int)i) == TRUE;
}
}
void DumpSectionGui::selectOrDeselectAll()
{
BOOL checkState = ListSectionSelect.GetCheckState((int)0) ? FALSE : TRUE;
for (size_t i = 0; i < sectionList.size(); i++)
{
ListSectionSelect.SetCheckState((int)i, checkState);
}
}
\ No newline at end of file
diff --git a/Scylla/DumpSectionGui.h b/Scylla/DumpSectionGui.h
index 17bfe02..5c433f8 100644
--- a/Scylla/DumpSectionGui.h
+++ b/Scylla/DumpSectionGui.h
@@ -1,127 +1,127 @@
#pragma once
#include <windows.h>
#include "resource.h"
// WTL
#include <atlbase.h> // base ATL classes
#include <atlapp.h> // base WTL classes
#include <atlwin.h> // ATL GUI classes
#include <atlframe.h> // WTL window frame helpers
#include <atlmisc.h> // WTL utility classes
#include <atlcrack.h> // WTL enhanced msg map macros
#include <atlctrls.h> // WTL controls
#include <atlddx.h> // WTL dialog data exchange
#include <vector>
#include "hexedit.h"
class PeSection
{
public:
WCHAR name[IMAGE_SIZEOF_SHORT_NAME + 1];
DWORD_PTR virtualAddress;
DWORD virtualSize;
- DWORD_PTR rawAddress;
+ DWORD rawAddress;
DWORD rawSize;
DWORD characteristics;
bool isDumped;
bool highlightVirtualSize();
};
class DumpSectionGui : public CDialogImpl<DumpSectionGui>, public CWinDataExchange<DumpSectionGui>, public CDialogResize<DumpSectionGui>
{
public:
enum { IDD = IDD_DLG_DUMPSECTION };
BEGIN_DDX_MAP(DumpSectionGui)
DDX_CONTROL_HANDLE(IDC_LIST_DUMPSECTION, ListSectionSelect)
DDX_CONTROL(IDC_EDIT_LISTCONTROL, EditListControl)
END_DDX_MAP()
BEGIN_MSG_MAP(DumpSectionGui)
MSG_WM_INITDIALOG(OnInitDialog)
NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, LVN_COLUMNCLICK, OnListSectionColumnClicked)
NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_CLICK, OnListSectionClick)
NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_CUSTOMDRAW, OnNMCustomdraw)
NOTIFY_HANDLER_EX(IDC_LIST_DUMPSECTION, NM_DBLCLK, OnListDoubleClick)
COMMAND_ID_HANDLER_EX(IDC_BUTTON_SELECT_DESELECT, OnSectionSelectAll)
COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPSECTION_OK, OnOK)
COMMAND_ID_HANDLER_EX(IDC_EDIT_LISTCONTROL, OnEditList)
COMMAND_ID_HANDLER_EX(IDC_BTN_DUMPSECTION_CANCEL, OnCancel)
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
CHAIN_MSG_MAP(CDialogResize<DumpSectionGui>)
END_MSG_MAP()
BEGIN_DLGRESIZE_MAP(DumpSectionGui)
DLGRESIZE_CONTROL(IDC_LIST_DUMPSECTION, DLSZ_SIZE_X | DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BTN_DUMPSECTION_OK, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BTN_DUMPSECTION_CANCEL, DLSZ_MOVE_X | DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_BUTTON_SELECT_DESELECT, DLSZ_MOVE_Y)
END_DLGRESIZE_MAP()
DumpSectionGui();
~DumpSectionGui();
DWORD_PTR imageBase; //VA
DWORD_PTR entryPoint;
WCHAR fullpath[MAX_PATH];
std::vector<PeSection> & getSectionList();
private:
CListViewCtrl ListSectionSelect;
CHexEdit<DWORD> EditListControl;
std::vector<PeSection> sectionList;
PeSection *selectedSection;
bool isEditing;
int editingSubItem;
DWORD valueBeforeEditing;
enum ListColumns {
COL_NAME = 0,
COL_VA,
COL_VSize,
COL_RVA,
COL_RSize,
COL_Characteristics
};
int prevColumn;
bool ascending;
// Message handlers
BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
LRESULT OnListSectionColumnClicked(NMHDR* pnmh);
LRESULT OnListSectionClick(NMHDR* pnmh);
LRESULT OnNMCustomdraw(NMHDR* pnmh);
LRESULT OnListDoubleClick(NMHDR* pnmh);
void OnSectionSelectAll(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnEditList(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnOK(UINT uNotifyCode, int nID, CWindow wndCtl);
void OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl);
// GUI functions
void addColumnsToSectionList(CListViewCtrl& list);
void displaySectionList(CListViewCtrl& list);
static int CALLBACK listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
WCHAR * getCharacteristicsString( DWORD characteristics );
void getAllSectionsFromFile();
void updateEditedItem();
void updateCheckState();
void selectOrDeselectAll();
};
\ No newline at end of file
diff --git a/Scylla/ImportRebuild.cpp b/Scylla/ImportRebuild.cpp
deleted file mode 100644
index c134187..0000000
--- a/Scylla/ImportRebuild.cpp
+++ /dev/null
@@ -1,717 +0,0 @@
-#include "ImportRebuild.h"
-
-#include "Scylla.h"
-#include "StringConversion.h"
-
-//#define DEBUG_COMMENTS
-
-ImportRebuild::ImportRebuild()
-{
- imageData = NULL;
- sizeOfFile = 0;
-
- pDosStub = NULL;
-
- pOverlay = NULL;
- sizeOfOverlay = 0;
-
- pImportDescriptor = NULL;
- pThunkData = NULL;
- pImportByName = NULL;
-
- numberOfImportDescriptors = 0;
- sizeOfImportSection = 0;
- sizeOfApiAndModuleNames = 0;
- importSectionIndex = 0;
-}
-
-ImportRebuild::~ImportRebuild()
-{
- delete [] pDosStub;
- delete [] imageData;
-
- for (size_t i = 0; i < vecSectionData.size(); i++)
- {
- delete [] vecSectionData[i];
- }
-
- delete [] pOverlay;
-}
-
-bool ImportRebuild::splitTargetFile()
-{
- PIMAGE_SECTION_HEADER pSecHeader = 0;
- BYTE * data = 0;
- DWORD alignment = 0;
-
- DosHeader = *(IMAGE_DOS_HEADER*)imageData;
-
- if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
- {
- return false;
- }
-
- NTHeader = *(IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew);
-
- if (NTHeader.Signature != IMAGE_NT_SIGNATURE)
- {
- return false;
- }
-
- if (DosHeader.e_lfanew > sizeof(IMAGE_DOS_HEADER))
- {
- size_t sizeOfStub = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
- pDosStub = new BYTE[sizeOfStub];
- CopyMemory(pDosStub, imageData + sizeof(IMAGE_DOS_HEADER), sizeOfStub);
- }
-
- pSecHeader = IMAGE_FIRST_SECTION((IMAGE_NT_HEADERS*)(imageData + DosHeader.e_lfanew));
-
- for (WORD i = 0; i < NTHeader.FileHeader.NumberOfSections; i++)
- {
- const DWORD SECTION_SIZE_MAX = 300000000;
- DWORD sizeOfSection = pSecHeader->SizeOfRawData;
-
- if (sizeOfSection > SECTION_SIZE_MAX)
- {
- sizeOfSection = SECTION_SIZE_MAX;
- }
-
- //TODO better use section alignment because it is better?
- alignment = alignValue(sizeOfSection, NTHeader.OptionalHeader.SectionAlignment);
- data = new BYTE[alignment];
-
- ZeroMemory(data, alignment);
- CopyMemory(data, imageData + pSecHeader->PointerToRawData, sizeOfSection);
-
- vecSectionData.push_back(data);
- vecSectionHeaders.push_back(*pSecHeader);
-
- pSecHeader++;
- }
-
- if(NTHeader.FileHeader.NumberOfSections > 0) // ??
- {
- const IMAGE_SECTION_HEADER* pLastSec = &(*vecSectionHeaders.rbegin());
- DWORD calcSize = pLastSec->PointerToRawData + pLastSec->SizeOfRawData;
- if (calcSize < sizeOfFile)
- {
- sizeOfOverlay = sizeOfFile - calcSize;
- pOverlay = new BYTE[sizeOfOverlay];
- memcpy(pOverlay, imageData + calcSize, sizeOfOverlay);
- }
- }
-
- delete [] imageData;
- imageData = 0;
-
- return true;
-}
-
-bool ImportRebuild::alignSectionHeaders()
-{
- for (WORD i = 0; i < vecSectionHeaders.size(); i++)
- {
- vecSectionHeaders[i].VirtualAddress = alignValue(vecSectionHeaders[i].VirtualAddress, NTHeader.OptionalHeader.SectionAlignment);
- vecSectionHeaders[i].Misc.VirtualSize = alignValue(vecSectionHeaders[i].Misc.VirtualSize, NTHeader.OptionalHeader.SectionAlignment);
-
- vecSectionHeaders[i].PointerToRawData = alignValue(vecSectionHeaders[i].PointerToRawData, NTHeader.OptionalHeader.FileAlignment);
- vecSectionHeaders[i].SizeOfRawData = alignValue(vecSectionHeaders[i].SizeOfRawData, NTHeader.OptionalHeader.FileAlignment);
- }
-
- return true;
-}
-
-bool ImportRebuild::saveNewFile(const WCHAR * filepath)
-{
- DWORD fileOffset = 0;
- DWORD dwWriteSize = 0;
- size_t i = 0;
-
- if (vecSectionHeaders.size() != vecSectionData.size())
- {
- return false;
- }
-
- HANDLE hFile = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, 0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-
- if(hFile == INVALID_HANDLE_VALUE)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveNewFile :: INVALID_HANDLE_VALUE %u", GetLastError());
-#endif
-
- return false;
- }
-
- //alignSectionHeaders();
- updatePeHeader();
-
- fileOffset = 0;
- dwWriteSize = sizeof(IMAGE_DOS_HEADER);
- ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &DosHeader);
-
- fileOffset += dwWriteSize;
- dwWriteSize = DosHeader.e_lfanew - sizeof(IMAGE_DOS_HEADER);
- ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, pDosStub);
-
- fileOffset += dwWriteSize;
- dwWriteSize = sizeof(IMAGE_NT_HEADERS);
- ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &NTHeader);
-
- fileOffset += dwWriteSize;
- dwWriteSize = sizeof(IMAGE_SECTION_HEADER);
-
- for (i = 0; i < vecSectionHeaders.size(); i++)
- {
- if (!ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, &vecSectionHeaders[i]))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveNewFile :: writeMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
-#endif
- CloseHandle(hFile);
- return false;
- }
- fileOffset += dwWriteSize;
- }
-
- for (i = 0; i < vecSectionHeaders.size(); i++)
- {
- dwWriteSize = vecSectionHeaders[i].PointerToRawData - fileOffset;
-
- if (dwWriteSize)
- {
- if (!writeZeroMemoryToFile(hFile, fileOffset, dwWriteSize))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveNewFile :: writeZeroMemoryToFile failed offset %X size %X", fileOffset, dwWriteSize);
-#endif
- CloseHandle(hFile);
- return false;
- }
- fileOffset += dwWriteSize;
- }
-
- dwWriteSize = vecSectionHeaders[i].SizeOfRawData;
-
- ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, dwWriteSize, vecSectionData[i]);
- fileOffset += dwWriteSize;
- }
-
- if(pOverlay)
- {
- ProcessAccessHelp::writeMemoryToFile(hFile, fileOffset, (DWORD)sizeOfOverlay, pOverlay);
- fileOffset += (DWORD)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};
-
- //DWORD sectionSize = calculateMinSize(moduleList);
- calculateImportSizes(moduleList);
-
- if (wcslen(Scylla::config[IAT_SECTION_NAME].getString()) > IMAGE_SIZEOF_SHORT_NAME)
- {
- strcpy_s(sectionName, ".SCY");
- }
- else
- {
- StringConversion::ToASCII(Scylla::config[IAT_SECTION_NAME].getString(), sectionName, _countof(sectionName));
- }
-
- return addNewSection(sectionName, (DWORD)sizeOfImportSection, 0);
-}
-
-/*DWORD ImportRebuild::calculateMinSize(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
-{
- DWORD dwSize = 0;
- std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
- std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
-
- dwSize = (DWORD)((moduleList.size() + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR)); //last is zero'ed
-
- for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
- {
-
- //dwSize += (DWORD)((*mapIt).second.thunkList.size() + sizeof(IMAGE_IMPORT_BY_NAME));
- dwSize += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
-
- for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
- {
- if((*mapIt2).second.name[0] != '\0')
- {
- dwSize += sizeof(IMAGE_IMPORT_BY_NAME);
- dwSize += (DWORD)strlen((*mapIt2).second.name);
- }
- }
- }
-
- return dwSize;
-}*/
-
-BYTE * ImportRebuild::getMemoryPointerFromRVA(DWORD_PTR dwRVA)
-{
- DWORD_PTR offset = convertRVAToOffsetVector((DWORD)dwRVA);
-
- for (size_t i = 0; i < vecSectionHeaders.size(); i++)
- {
- if ((vecSectionHeaders[i].PointerToRawData <= offset) && ((vecSectionHeaders[i].PointerToRawData + vecSectionHeaders[i].SizeOfRawData) > offset))
- {
- return (BYTE *)((DWORD_PTR)vecSectionData[i] + (offset - vecSectionHeaders[i].PointerToRawData));
- }
- }
-
- return 0;
-}
-
-DWORD ImportRebuild::fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList )
-{
- std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
- std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
- PIMAGE_IMPORT_DESCRIPTOR pImportDesc = 0;
- PIMAGE_IMPORT_BY_NAME pImportByName = 0;
- PIMAGE_THUNK_DATA pThunk = 0;
- ImportModuleThunk * importModuleThunk = 0;
- ImportThunk * importThunk = 0;
-
- size_t stringLength = 0;
- DWORD_PTR lastRVA = 0;
-
- BYTE * sectionData = vecSectionData[importSectionIndex];
- DWORD offset = 0;
-
- pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(sectionData);
-
- //skip the IMAGE_IMPORT_DESCRIPTOR
- offset += (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
-
- for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
- {
- importModuleThunk = &((*mapIt).second);
-
- stringLength = addImportDescriptor(importModuleThunk, offset);
-
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"fillImportSection :: importDesc.Name %X", pImportDescriptor->Name);
-#endif
-
- offset += (DWORD)stringLength; //stringLength has null termination char
-
- pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)sectionData + offset);
-
- //pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importModuleThunk->firstThunk));
-
- lastRVA = importModuleThunk->firstThunk - sizeof(DWORD_PTR);
-
- for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
- {
- importThunk = &((*mapIt2).second);
-
- pThunk = (PIMAGE_THUNK_DATA)(getMemoryPointerFromRVA(importThunk->rva));
-
- //check wrong iat pointer
- if (!pThunk)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"fillImportSection :: Failed to get pThunk RVA: %X", importThunk->rva);
-#endif
- return 0;
- }
-
- if ((lastRVA + sizeof(DWORD_PTR)) != importThunk->rva)
- {
- //add additional import desc
- addSpecialImportDescriptor(importThunk->rva);
- }
- lastRVA = importThunk->rva;
-
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"fillImportSection :: importThunk %X pThunk %X pImportByName %X offset %X", importThunk,pThunk,pImportByName,offset);
-#endif
- stringLength = addImportToImportTable(importThunk, pThunk, pImportByName, offset);
-
- offset += (DWORD)stringLength; //is 0 bei import by ordinal
- pImportByName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)pImportByName + stringLength);
- }
-
- pImportDescriptor++;
- }
-
- return offset;
-}
-
-bool ImportRebuild::rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
-{
- bool retValue = false;
-
- if (loadTargetFile(targetFilePath))
- {
- splitTargetFile();
-
- retValue = buildNewImportTable(moduleList);
-
- if (retValue)
- {
- retValue = saveNewFile(newFilePath);
- }
-
- return retValue;
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"rebuildImportTable ::Failed to load target %s", targetFilePath);
-#endif
- return false;
- }
-}
-
-void ImportRebuild::setFlagToIATSection(DWORD_PTR iatAddress)
-{
- for (size_t i = 0; i < vecSectionHeaders.size(); i++)
- {
- if ((vecSectionHeaders[i].VirtualAddress <= iatAddress) && ((vecSectionHeaders[i].VirtualAddress + vecSectionHeaders[i].Misc.VirtualSize) > iatAddress))
- {
- //section must be read and writeable
- vecSectionHeaders[i].Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- }
- }
-}
-
-size_t ImportRebuild::addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset)
-{
- size_t stringLength = 0;
-
- if(pImport->name[0] == '\0')
- {
- pThunk->u1.AddressOfData = (IMAGE_ORDINAL(pImport->ordinal) | IMAGE_ORDINAL_FLAG);
- }
- else
- {
- pImportByName->Hint = pImport->hint;
-
- stringLength = strlen(pImport->name) + 1;
- memcpy(pImportByName->Name, pImport->name, stringLength);
-
- pThunk->u1.AddressOfData = convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
-
- if (!pThunk->u1.AddressOfData)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", vecSectionHeaders[importSectionIndex].PointerToRawData, sectionOffset);
-#endif
- }
-
- //next import should be nulled
- pThunk++;
- pThunk->u1.AddressOfData = 0;
-
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"addImportToImportTable :: pThunk->u1.AddressOfData %X %X %X", pThunk->u1.AddressOfData, pThunk, vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
-#endif
- stringLength += sizeof(WORD);
- }
-
- return stringLength;
-}
-
-size_t ImportRebuild::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset)
-{
- char dllName[MAX_PATH];
-
- StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName));
- size_t stringLength = strlen(dllName) + 1;
-
- /*
- Warning: stringLength MUST include null termination char
- */
-
- memcpy((vecSectionData[importSectionIndex] + sectionOffset), dllName, stringLength); //copy module name to section
-
- pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk;
- pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(vecSectionHeaders[importSectionIndex].PointerToRawData + sectionOffset);
-
- return stringLength;
-}
-
-void ImportRebuild::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk)
-{
- PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor;
- pImportDescriptor++;
-
- pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk;
- pImportDescriptor->Name = oldID->Name;
-}
-
-void ImportRebuild::calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
-{
- std::map<DWORD_PTR, ImportModuleThunk>::iterator mapIt;
- std::map<DWORD_PTR, ImportThunk>::iterator mapIt2;
- DWORD_PTR lastRVA = 0;
-
- numberOfImportDescriptors = 0;
- sizeOfImportSection = 0;
- sizeOfApiAndModuleNames = 0;
-
- numberOfImportDescriptors = moduleList.size() + 1; //last is zero'd
-
- for ( mapIt = moduleList.begin() ; mapIt != moduleList.end(); mapIt++ )
- {
- lastRVA = (*mapIt).second.firstThunk - sizeof(DWORD_PTR);
-
- sizeOfApiAndModuleNames += (DWORD)(wcslen((*mapIt).second.moduleName) + 1);
-
- for ( mapIt2 = (*mapIt).second.thunkList.begin() ; mapIt2 != (*mapIt).second.thunkList.end(); mapIt2++ )
- {
- if ((lastRVA + sizeof(DWORD_PTR)) != (*mapIt2).second.rva)
- {
- numberOfImportDescriptors++; //add additional import desc
- }
-
- if((*mapIt2).second.name[0] != '\0')
- {
- sizeOfApiAndModuleNames += sizeof(WORD); //Hint from IMAGE_IMPORT_BY_NAME
- sizeOfApiAndModuleNames += (DWORD)(strlen((*mapIt2).second.name) + 1);
- }
-
- lastRVA = (*mapIt2).second.rva;
- }
- }
-
- sizeOfImportSection = sizeOfApiAndModuleNames + (numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
-}
\ No newline at end of file
diff --git a/Scylla/ImportRebuild.h b/Scylla/ImportRebuild.h
deleted file mode 100644
index 27bad7f..0000000
--- a/Scylla/ImportRebuild.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#pragma once
-
-#include <map>
-#include "ProcessAccessHelp.h"
-#include "Thunks.h"
-
-class ImportRebuild
-{
-public:
-
- ImportRebuild();
- ~ImportRebuild();
-
- bool rebuildImportTable(const WCHAR * targetFilePath, const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
-
- //DWORD convertRVAToOffset(DWORD dwRVA);
- //DWORD convertOffsetToRVA(DWORD dwOffset);
-
- bool addNewSection(char * sectionName, DWORD sectionSize, BYTE * sectionData);
-
- bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size);
-
-private:
- std::vector<IMAGE_SECTION_HEADER> vecSectionHeaders;
- std::vector<BYTE *> vecSectionData;
-
- BYTE * imageData;
- size_t sizeOfFile;
-
- BYTE * pDosStub;
- IMAGE_DOS_HEADER DosHeader;
- IMAGE_NT_HEADERS NTHeader;
-
- BYTE * pOverlay;
- size_t sizeOfOverlay;
-
- PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
- PIMAGE_THUNK_DATA pThunkData;
- PIMAGE_IMPORT_BY_NAME pImportByName;
-
- size_t numberOfImportDescriptors;
- size_t sizeOfImportSection;
- size_t sizeOfApiAndModuleNames;
- size_t importSectionIndex;
-
- DWORD getOffsetLastSection();
-
- void updatePeHeader();
- DWORD fillImportSection( std::map<DWORD_PTR, ImportModuleThunk> & moduleList );
- bool splitTargetFile();
-
- DWORD convertRVAToOffsetVector(DWORD dwRVA);
- DWORD_PTR convertOffsetToRVAVector(DWORD dwOffset);
-
- BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA);
-
- DWORD alignValue(DWORD badValue, DWORD alignTo);
-
- bool alignSectionHeaders();
-
- bool saveNewFile(const WCHAR * filepath);
- bool loadTargetFile(const WCHAR * filepath);
-
- bool createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
- bool buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
- void setFlagToIATSection( DWORD_PTR iatAddress );
- size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset);
- size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset);
-
- void calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
-
- void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk);
-};
\ No newline at end of file
diff --git a/Scylla/ImportRebuilder.cpp b/Scylla/ImportRebuilder.cpp
new file mode 100644
index 0000000..016d3dd
--- /dev/null
+++ b/Scylla/ImportRebuilder.cpp
@@ -0,0 +1,288 @@
+
+#include "ImportRebuilder.h"
+#include "Scylla.h"
+#include "StringConversion.h"
+
+#define DEBUG_COMMENTS
+
+
+bool ImportRebuilder::rebuildImportTable(const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
+{
+ bool retValue = false;
+
+ if (isValidPeFile())
+ {
+ if (readPeSectionsFromFile())
+ {
+ setDefaultFileAlignment();
+
+ retValue = buildNewImportTable(moduleList);
+
+ if (retValue)
+ {
+ alignAllSectionHeaders();
+ fixPeHeader();
+ retValue = savePeFileToDisk(newFilePath);
+ }
+ }
+ }
+
+ return retValue;
+}
+
+bool ImportRebuilder::buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
+{
+ createNewImportSection(moduleList);
+
+ importSectionIndex = listPeSection.size() - 1;
+
+ DWORD dwSize = fillImportSection(moduleList);
+
+ if (!dwSize)
+ {
+ return false;
+ }
+
+ setFlagToIATSection((*moduleList.begin()).second.firstThunk);
+
+ if (isPE32())
+ {
+ pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress;
+ pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
+ }
+ else
+ {
+ pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = listPeSection[importSectionIndex].sectionHeader.VirtualAddress;
+ pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)(numberOfImportDescriptors * sizeof(IMAGE_IMPORT_DESCRIPTOR));
+ }
+
+
+ return true;
+}
+
+bool ImportRebuilder::createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList)
+{
+ char sectionName[IMAGE_SIZEOF_SHORT_NAME + 1] = {0};
+
+ const WCHAR * sectionNameW = Scylla::config[IAT_SECTION_NAME].getString();
+
+ calculateImportSizes(moduleList);
+
+ if (wcslen(sectionNameW) > IMAGE_SIZEOF_SHORT_NAME)
+ {
+ strcpy_s(sectionName, ".SCY");
+ }
+ else
+ {
+ StringConversion::ToASCII(sectionNameW, sectionName, _countof(sectionName));
+ }
+
+ return addNewLastSection(sectionName, (DWORD)sizeOfImportSection, 0);
+}
+
+void ImportRebuilder::setFlagToIATSection(DWORD_PTR iatAddress)
+{
+ for (size_t i = 0; i < listPeSection.size(); i++)
+ {
+ if ((listPeSection[i].sectionHeader.VirtualAddress <= iatAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > iatAddress))
+ {
+ //section must be read and writeable
+ listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+ }
+ }
+}
+
+DWORD ImportRebuilder::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 = listPeSection[importSectionIndex].data;
+ 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;
+}
+
+size_t ImportRebuilder::addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset)
+{
+ char dllName[MAX_PATH];
+
+ StringConversion::ToASCII(pImportModule->moduleName, dllName, _countof(dllName));
+ size_t stringLength = strlen(dllName) + 1;
+
+ /*
+ Warning: stringLength MUST include null termination char
+ */
+
+ memcpy((listPeSection[importSectionIndex].data + sectionOffset), dllName, stringLength); //copy module name to section
+
+ pImportDescriptor->FirstThunk = (DWORD)pImportModule->firstThunk;
+ pImportDescriptor->Name = (DWORD)convertOffsetToRVAVector(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset);
+
+ return stringLength;
+}
+
+void ImportRebuilder::addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk)
+{
+ PIMAGE_IMPORT_DESCRIPTOR oldID = pImportDescriptor;
+ pImportDescriptor++;
+
+ pImportDescriptor->FirstThunk = (DWORD)rvaFirstThunk;
+ pImportDescriptor->Name = oldID->Name;
+}
+
+void ImportRebuilder::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));
+}
+
+size_t ImportRebuilder::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(listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset);
+
+ if (!pThunk->u1.AddressOfData)
+ {
+#ifdef DEBUG_COMMENTS
+ Scylla::debugLog.log(L"addImportToImportTable :: failed to get AddressOfData %X %X", listPeSection[importSectionIndex].sectionHeader.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, listPeSection[importSectionIndex].sectionHeader.PointerToRawData + sectionOffset);
+#endif
+ stringLength += sizeof(WORD);
+ }
+
+ return stringLength;
+}
+
+BYTE * ImportRebuilder::getMemoryPointerFromRVA(DWORD_PTR dwRVA)
+{
+ DWORD_PTR offset = convertRVAToOffsetVector(dwRVA);
+
+ for (size_t i = 0; i < listPeSection.size(); i++)
+ {
+ if ((listPeSection[i].sectionHeader.PointerToRawData <= offset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > offset))
+ {
+ return (BYTE *)((DWORD_PTR)listPeSection[i].data + (offset - listPeSection[i].sectionHeader.PointerToRawData));
+ }
+ }
+
+ return 0;
+}
+
diff --git a/Scylla/ImportRebuilder.h b/Scylla/ImportRebuilder.h
new file mode 100644
index 0000000..e176bae
--- /dev/null
+++ b/Scylla/ImportRebuilder.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <map>
+#include "PeParser.h"
+#include "Thunks.h"
+
+
+class ImportRebuilder : public PeParser {
+public:
+ ImportRebuilder(const WCHAR * file) : PeParser(file, true)
+ {
+ pImportDescriptor = 0;
+ pThunkData = 0;
+ pImportByName = 0;
+
+ numberOfImportDescriptors = 0;
+ sizeOfImportSection = 0;
+ sizeOfApiAndModuleNames = 0;
+ importSectionIndex = 0;
+ }
+
+ bool rebuildImportTable(const WCHAR * newFilePath, std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
+
+private:
+ PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor;
+ PIMAGE_THUNK_DATA pThunkData;
+ PIMAGE_IMPORT_BY_NAME pImportByName;
+
+ size_t numberOfImportDescriptors;
+ size_t sizeOfImportSection;
+ size_t sizeOfApiAndModuleNames;
+ size_t importSectionIndex;
+
+ DWORD fillImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
+ BYTE * getMemoryPointerFromRVA(DWORD_PTR dwRVA);
+
+ bool createNewImportSection(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
+ bool buildNewImportTable(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
+ void setFlagToIATSection(DWORD_PTR iatAddress);
+ size_t addImportToImportTable( ImportThunk * pImport, PIMAGE_THUNK_DATA pThunk, PIMAGE_IMPORT_BY_NAME pImportByName, DWORD sectionOffset);
+ size_t addImportDescriptor(ImportModuleThunk * pImportModule, DWORD sectionOffset);
+
+ void calculateImportSizes(std::map<DWORD_PTR, ImportModuleThunk> & moduleList);
+
+ void addSpecialImportDescriptor(DWORD_PTR rvaFirstThunk);
+};
\ No newline at end of file
diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp
index 22ccdda..a40e1c2 100644
--- a/Scylla/MainGui.cpp
+++ b/Scylla/MainGui.cpp
@@ -1,1365 +1,1386 @@
#include "MainGui.h"
#include "Architecture.h"
//#include "PluginLoader.h"
//#include "ConfigurationHolder.h"
//#include "PeDump.h"
//#include "PeRebuild.h"
#include "PeParser.h"
#include "DllInjectionPlugin.h"
#include "DisassemblerGui.h"
#include "PickApiGui.h"
//#include "NativeWinApi.h"
-#include "ImportRebuild.h"
+//#include "ImportRebuild.h"
+#include "ImportRebuilder.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";
const WCHAR MainGui::filterMem[] = L"MEM file (*.mem)\0*.mem\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::OnDumpMemory(UINT uNotifyCode, int nID, CWindow wndCtl)
{
dumpMemoryActionHandler();
}
void MainGui::OnDumpSection(UINT uNotifyCode, int nID, CWindow wndCtl)
{
dumpSectionActionHandler();
}
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, 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, 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, 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, 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, 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];
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, false, NULL, filterXml, NULL, stringBuffer))
{
TreeImportExport treeIO(selectedFilePath);
DWORD_PTR addrOEP = 0;
DWORD_PTR addrIAT = 0;
DWORD sizeIAT = 0;
if(!treeIO.importTreeList(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];
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, NULL, filterXml, L"xml", stringBuffer))
{
TreeImportExport treeIO(selectedFilePath);
DWORD_PTR addrOEP = EditOEPAddress.GetValue();
DWORD_PTR addrIAT = EditIATAddress.GetValue();
DWORD sizeIAT = EditIATSize.GetValue();
if(!treeIO.exportTreeList(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, 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::dumpMemoryActionHandler()
{
WCHAR selectedFilePath[MAX_PATH];
DumpMemoryGui dlgDumpMemory;
if(dlgDumpMemory.DoModal())
{
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, dlgDumpMemory.dumpFilename, filterMem, L"mem", stringBuffer))
{
if (ProcessAccessHelp::writeMemoryToNewFile(selectedFilePath,dlgDumpMemory.dumpedMemorySize,dlgDumpMemory.dumpedMemory))
{
Scylla::windowLog.log(L"Memory dump saved %s", selectedFilePath);
}
else
{
Scylla::windowLog.log(L"Error! Cannot write memory dump to disk");
}
}
}
}
void MainGui::dumpSectionActionHandler()
{
WCHAR selectedFilePath[MAX_PATH];
DumpSectionGui dlgDumpSection;
const WCHAR * fileFilter;
const WCHAR * defExtension;
PeParser * peFile = 0;
dlgDumpSection.entryPoint = EditOEPAddress.GetValue();
if (ProcessAccessHelp::selectedModule)
{
//dump DLL
fileFilter = filterDll;
defExtension = L"dll";
dlgDumpSection.imageBase = ProcessAccessHelp::selectedModule->modBaseAddr;
//get it from gui
wcscpy_s(dlgDumpSection.fullpath, ProcessAccessHelp::selectedModule->fullPath);
}
else
{
fileFilter = filterExe;
defExtension = L"exe";
dlgDumpSection.imageBase = ProcessAccessHelp::targetImageBase;
//get it from gui
wcscpy_s(dlgDumpSection.fullpath, selectedProcess->fullPath);
}
if(dlgDumpSection.DoModal())
{
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, true, NULL, fileFilter, defExtension, stringBuffer))
{
if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue())
{
peFile = new PeParser(dlgDumpSection.fullpath, true);
}
else
{
peFile = new PeParser(dlgDumpSection.imageBase, true);
}
std::vector<PeSection> & sectionList = dlgDumpSection.getSectionList();
if (peFile->dumpProcess(dlgDumpSection.imageBase, dlgDumpSection.entryPoint, selectedFilePath, sectionList))
{
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);
}
delete peFile;
}
}
}
void MainGui::dumpActionHandler()
{
if(!selectedProcess)
return;
WCHAR selectedFilePath[MAX_PATH];
const WCHAR * fileFilter;
const WCHAR * defExtension;
DWORD_PTR modBase = 0;
DWORD_PTR entrypoint = 0;
WCHAR * filename = 0;
PeParser * peFile = 0;
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))
{
entrypoint = EditOEPAddress.GetValue();
if (ProcessAccessHelp::selectedModule)
{
//dump DLL
modBase = ProcessAccessHelp::selectedModule->modBaseAddr;
filename = ProcessAccessHelp::selectedModule->fullPath;
}
else
{
//dump exe
modBase = ProcessAccessHelp::targetImageBase;
filename = selectedProcess->fullPath;
}
if (Scylla::config[USE_PE_HEADER_FROM_DISK].isTrue())
{
peFile = new PeParser(filename, true);
}
else
{
peFile = new PeParser(modBase, true);
}
if (peFile->dumpProcess(modBase, entrypoint, 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);
}
delete peFile;
}
}
void MainGui::peRebuildActionHandler()
{
DWORD newSize = 0;
WCHAR selectedFilePath[MAX_PATH];
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if(showFileDialog(selectedFilePath, false, NULL, filterExeDll, NULL, stringBuffer))
{
if (Scylla::config[CREATE_BACKUP].isTrue())
{
if (!ProcessAccessHelp::createBackupFile(selectedFilePath))
{
Scylla::windowLog.log(L"Creating backup file failed %s", selectedFilePath);
}
}
DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath);
PeParser peFile(selectedFilePath, true);
if (peFile.readPeSectionsFromFile())
{
peFile.setDefaultFileAlignment();
if (Scylla::config[REMOVE_DOS_HEADER_STUB].isTrue())
{
peFile.removeDosStub();
}
peFile.alignAllSectionHeaders();
peFile.fixPeHeader();
if (peFile.savePeFileToDisk(selectedFilePath))
{
newSize = (DWORD)ProcessAccessHelp::getFileSize(selectedFilePath);
+ if (Scylla::config[UPDATE_HEADER_CHECKSUM].isTrue())
+ {
+ Scylla::windowLog.log(L"Generating PE header checksum");
+ if (!PeParser::updatePeHeaderChecksum(selectedFilePath, newSize))
+ {
+ Scylla::windowLog.log(L"Generating PE header checksum FAILED!");
+ }
+ }
+
Scylla::windowLog.log(L"Rebuild success %s", selectedFilePath);
Scylla::windowLog.log(L"-> Old file size 0x%08X new file size 0x%08X (%d %%)", fileSize, newSize, ((newSize * 100) / fileSize) );
}
else
{
Scylla::windowLog.log(L"Rebuild failed, cannot save file %s", selectedFilePath);
MessageBox(L"Rebuild failed. Cannot save file.", L"Failure", MB_ICONERROR);
}
}
else
{
Scylla::windowLog.log(L"Rebuild failed, cannot read file %s", selectedFilePath);
MessageBox(L"Rebuild failed. Cannot read file.", L"Failure", MB_ICONERROR);
}
}
}
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;
+ DWORD_PTR modBase = 0;
+ DWORD_PTR entrypoint = EditOEPAddress.GetValue();
if (ProcessAccessHelp::selectedModule)
{
+ modBase = ProcessAccessHelp::selectedModule->modBaseAddr;
fileFilter = filterDll;
}
else
{
+ modBase = ProcessAccessHelp::targetImageBase;
fileFilter = filterExe;
}
getCurrentModulePath(stringBuffer, _countof(stringBuffer));
if (showFileDialog(selectedFilePath, false, NULL, fileFilter, NULL, stringBuffer))
{
wcscpy_s(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, L"_SCY");
if(extension)
{
wcscat_s(newFilePath, extension);
}
- ImportRebuild importRebuild;
- if (importRebuild.rebuildImportTable(selectedFilePath,newFilePath,importsHandling.moduleList))
+ ImportRebuilder importRebuild(selectedFilePath);
+
+ if (Scylla::config[IAT_FIX_AND_OEP_FIX].isTrue())
+ {
+ importRebuild.setEntryPointRva((DWORD)(entrypoint - modBase));
+ }
+
+
+ if (importRebuild.rebuildImportTable(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_DUMPMEMORY, valMenu);
menu.EnableMenuItem(ID_FILE_DUMPSECTION, 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[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(WCHAR * 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/MainGui.rc b/Scylla/MainGui.rc
index 544a714..3bc169c 100644
Binary files a/Scylla/MainGui.rc and b/Scylla/MainGui.rc differ
diff --git a/Scylla/OptionsGui.cpp b/Scylla/OptionsGui.cpp
index 39083ac..3d1eb25 100644
--- a/Scylla/OptionsGui.cpp
+++ b/Scylla/OptionsGui.cpp
@@ -1,52 +1,54 @@
#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() const
{
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);
Scylla::config[REMOVE_DOS_HEADER_STUB].setBool(removeDosHeaderStub);
+ Scylla::config[IAT_FIX_AND_OEP_FIX].setBool(fixIatAndOep);
}
void OptionsGui::loadOptions()
{
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);
iatSectionName[_countof(iatSectionName) - 1] = L'\0';
removeDosHeaderStub = Scylla::config[REMOVE_DOS_HEADER_STUB].getBool();
+ fixIatAndOep = Scylla::config[IAT_FIX_AND_OEP_FIX].getBool();
}
diff --git a/Scylla/OptionsGui.h b/Scylla/OptionsGui.h
index 6e94ca3..1e600fa 100644
--- a/Scylla/OptionsGui.h
+++ b/Scylla/OptionsGui.h
@@ -1,65 +1,67 @@
#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)
DDX_CHECK(IDC_CHECK_REMOVE_DOS_STUB, removeDosHeaderStub)
+ DDX_CHECK(IDC_CHECK_FIX_IAT_AND_OEP, fixIatAndOep)
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;
bool removeDosHeaderStub;
+ bool fixIatAndOep;
// 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() const;
void loadOptions();
};
diff --git a/Scylla/PeDump.cpp b/Scylla/PeDump.cpp
deleted file mode 100644
index 8da6b6b..0000000
--- a/Scylla/PeDump.cpp
+++ /dev/null
@@ -1,383 +0,0 @@
-#include "PeDump.h"
-#include "ProcessAccessHelp.h"
-
-#include "Scylla.h"
-#include "Architecture.h"
-#include "PeParser.h"
-
-bool PeDump::useHeaderFromDisk = true;
-bool PeDump::appendOverlayData = true;
-
-//#define DEBUG_COMMENTS
-
-bool PeDump::fillPeHeaderStructs(bool fromDisk)
-{
- DWORD dwSize = ProcessAccessHelp::PE_HEADER_BYTES_COUNT;
-
- if (dwSize > sizeOfImage)
- {
- dwSize = (DWORD)sizeOfImage;
- }
-
- headerData = new BYTE[dwSize];
-
- if (!headerData)
- return false;
-
- if (fromDisk)
- {
- //from disk
- if (!ProcessAccessHelp::readHeaderFromFile(headerData, dwSize, fullpath))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readHeaderFromFile failed - %X %s", dwSize, fullpath);
-#endif
- return false;
- }
- }
- else
- {
- //from memory
- if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase, dwSize, headerData))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"fillPeHeaderStructs -> ProcessAccessHelp::readMemoryFromProcess failed - " PRINTF_DWORD_PTR_FULL L" %X " PRINTF_DWORD_PTR_FULL, imageBase, dwSize, headerData);
-#endif
- return false;
- }
- }
-
- pDOSHeader = (PIMAGE_DOS_HEADER)headerData;
- pNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)headerData + (DWORD_PTR)pDOSHeader->e_lfanew);
- pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader);
-
- return true;
-}
-
-bool PeDump::validateHeaders()
-{
- if ((pDOSHeader != 0) && (pDOSHeader->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;
- }
-}
-
-bool PeDump::dumpCompleteProcessToDisk(const WCHAR * dumpFilePath)
-{
- if (!fillPeHeaderStructs(useHeaderFromDisk))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> fillPeHeaderStructs failed");
-#endif
- return false;
- }
-
- if (!validateHeaders())
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> validateHeaders failed");
-#endif
- return false;
- }
-
- dumpData = new BYTE[sizeOfImage];
-
- if (dumpData)
- {
- if (!ProcessAccessHelp::readMemoryPartlyFromProcess(imageBase,sizeOfImage,dumpData))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> readMemoryFromProcess failed");
-#endif
- return false;
- }
- else
- {
-
- fixDump(dumpData);
-
- if (saveDumpToDisk(dumpFilePath, dumpData, (DWORD)sizeOfImage))
- {
-
- if (appendOverlayData)
- {
- appendOverlayDataToDump(dumpFilePath);
- }
-
- //printf("dump success\n");
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"dumpCompleteProcessToDisk -> new BYTE[sizeOfImage] failed %X", sizeOfImage);
-#endif
- return false;
- }
-}
-
-bool PeDump::appendOverlayDataToDump(const WCHAR *dumpFilePath)
-{
- DWORD_PTR offset = 0;
- DWORD size = 0;
-
- if (getOverlayData(fullpath,&offset,&size))
- {
- if (offset == 0)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"appendOverlayDataToDump :: No overlay exists");
-#endif
- return true;
- }
- else
- {
- if (copyFileDataFromOffset(fullpath, dumpFilePath, offset, size))
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay success");
-#endif
- return true;
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"appendOverlayDataToDump :: appending overlay failed");
-#endif
- return false;
- }
- }
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"appendOverlayDataToDump :: getOverlayData failed");
-#endif
- return false;
- }
-}
-
-bool PeDump::copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize)
-{
- HANDLE hSourceFile, hDestFile;
- BYTE * dataBuffer = 0;
- bool retValue = false;
-
- hSourceFile = CreateFile(sourceFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
-
- if(hSourceFile == INVALID_HANDLE_VALUE)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open source file");
-#endif
- return false;
- }
-
- hDestFile = CreateFile(destFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
-
- if(hSourceFile == INVALID_HANDLE_VALUE)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"copyFileDataFromOffset :: failed to open destination file");
-#endif
- CloseHandle(hSourceFile);
- return false;
- }
-
- dataBuffer = new BYTE[dwSize];
-
- if (ProcessAccessHelp::readMemoryFromFile(hSourceFile, (LONG)fileOffset, dwSize, dataBuffer))
- {
- if (ProcessAccessHelp::writeMemoryToFileEnd(hDestFile,dwSize,dataBuffer))
- {
- retValue = true;
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"copyFileDataFromOffset :: writeMemoryToFileEnd failed");
-#endif
- retValue = false;
- }
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"copyFileDataFromOffset :: readMemoryFromFile failed to read from source file");
-#endif
- retValue = false;
- }
-
- delete [] dataBuffer;
-
- CloseHandle(hSourceFile);
- CloseHandle(hDestFile);
-
- return retValue;
-}
-
-void PeDump::fixDump(BYTE * dumpBuffer)
-{
- int counter = 0;
- PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dumpBuffer;
- PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)((DWORD_PTR)dumpBuffer + pDos->e_lfanew);
- PIMAGE_SECTION_HEADER pSec = IMAGE_FIRST_SECTION(pNt);
-
- fixNtHeaderForDump(pNt, pNTHeader);
-
- do
- {
- fixSectionHeaderForDump(pSec, pSectionHeader);
-
- pSectionHeader++;
- pSec++;
-
- counter++;
- } while (counter < pNt->FileHeader.NumberOfSections);
-
-
-}
-
-void PeDump::fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead)
-{
- //maybe imagebase in process is not real imagebase
- pNtHead->OptionalHeader.ImageBase = imageBase;
- pNtHead->OptionalHeader.AddressOfEntryPoint = (DWORD)(entryPoint - imageBase);
- pNtHead->OptionalHeader.SizeOfImage = sizeOfImage;
-}
-
-void PeDump::fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead)
-{
- memcpy_s(oldSecHead->Name, IMAGE_SIZEOF_SHORT_NAME, newSecHead->Name, IMAGE_SIZEOF_SHORT_NAME);
-
- oldSecHead->Characteristics = newSecHead->Characteristics;
-
- oldSecHead->Misc.VirtualSize = newSecHead->Misc.VirtualSize;
- oldSecHead->VirtualAddress = newSecHead->VirtualAddress;
-
- oldSecHead->SizeOfRawData = newSecHead->Misc.VirtualSize;
- oldSecHead->PointerToRawData = newSecHead->VirtualAddress;
-}
-
-void PeDump::fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead)
-{
- //some special
- fixBadNtHeaderValues(newNtHead);
-
- //fix FileHeader
- oldNtHead->FileHeader.NumberOfSections = newNtHead->FileHeader.NumberOfSections;
-
- //fix OptionalHeader
- oldNtHead->OptionalHeader.ImageBase = newNtHead->OptionalHeader.ImageBase;
- oldNtHead->OptionalHeader.SizeOfImage = newNtHead->OptionalHeader.SizeOfImage;
- oldNtHead->OptionalHeader.BaseOfCode = newNtHead->OptionalHeader.BaseOfCode;
- oldNtHead->OptionalHeader.AddressOfEntryPoint = newNtHead->OptionalHeader.AddressOfEntryPoint;
- oldNtHead->OptionalHeader.SectionAlignment = newNtHead->OptionalHeader.SectionAlignment;
- oldNtHead->OptionalHeader.FileAlignment = newNtHead->OptionalHeader.SectionAlignment;
-
- //deleted in x64 PE
-#ifndef _WIN64
- oldNtHead->OptionalHeader.BaseOfData = newNtHead->OptionalHeader.BaseOfData;
-#endif
-}
-
-bool PeDump::saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize)
-{
- DWORD lpNumberOfBytesWritten = 0;
- bool retValue = false;
-
- HANDLE hFile = CreateFile(dumpFilePath, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
-
- if(hFile == INVALID_HANDLE_VALUE)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveDumpToDisk :: INVALID_HANDLE_VALUE %u", GetLastError());
-#endif
- retValue = false;
- }
- else
- {
- if (WriteFile(hFile, dumpBuffer, dumpSize, &lpNumberOfBytesWritten, 0))
- {
- if (lpNumberOfBytesWritten != dumpSize)
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveDumpToDisk :: lpNumberOfBytesWritten != dumpSize %d %d", lpNumberOfBytesWritten,dumpSize);
-#endif
- retValue = false;
- }
- else
- {
- retValue = true;
- }
- }
- else
- {
-#ifdef DEBUG_COMMENTS
- Scylla::debugLog.log(L"saveDumpToDisk :: WriteFile failed %u",GetLastError());
-#endif
- retValue = false;
- }
-
- CloseHandle(hFile);
- }
-
- return retValue;
-}
-
-bool PeDump::getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize)
-{
- LONGLONG fileSize = 0;
- bool returnValue = false;
- DWORD calcSize = 0;
-
- PeParser peFile(filepath);
-
- if (peFile.isValidPeFile())
- {
- fileSize = ProcessAccessHelp::getFileSize(fullpath);
-
- if (fileSize > 0)
- {
- calcSize = peFile.getSectionHeaderBasedFileSize();
-
- if (calcSize < fileSize)
- {
- //overlay found
- *overlayFileOffset = calcSize;
- *overlaySize = (DWORD)(fileSize - calcSize);
- }
- else
- {
- *overlayFileOffset = 0;
- *overlaySize = 0;
- }
-
- returnValue = true;
- }
-
- }
-
- return returnValue;
-}
\ No newline at end of file
diff --git a/Scylla/PeDump.h b/Scylla/PeDump.h
deleted file mode 100644
index 6f7785e..0000000
--- a/Scylla/PeDump.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#pragma once
-
-#include <windows.h>
-
-class PeDump
-{
-public:
-
- DWORD_PTR entryPoint; //VA
- DWORD_PTR imageBase; //VA
- DWORD sizeOfImage;
- WCHAR fullpath[MAX_PATH];
-
- //Settings
- static bool useHeaderFromDisk;
- static bool appendOverlayData;
-
- PeDump()
- {
- imageBase = 0;
- sizeOfImage = 0;
- dumpData = 0;
- headerData = 0;
- pNTHeader = 0;
- pDOSHeader = 0;
- pSectionHeader = 0;
- }
-
- ~PeDump()
- {
- if (dumpData != 0)
- {
- delete [] dumpData;
- }
-
- if (headerData != 0)
- {
- delete [] headerData;
- }
- }
-
- bool dumpCompleteProcessToDisk(const WCHAR * dumpFilePath);
-
- bool saveDumpToDisk(const WCHAR * dumpFilePath, BYTE *dumpBuffer, DWORD dumpSize);
-
-
- bool copyFileDataFromOffset(const WCHAR * sourceFile, const WCHAR * destFile, DWORD_PTR fileOffset, DWORD dwSize);
- bool appendOverlayDataToDump(const WCHAR * dumpFilePath);
- bool getOverlayData(const WCHAR * filepath, DWORD_PTR * overlayFileOffset, DWORD * overlaySize);
-
-private:
-
- BYTE * dumpData;
- BYTE * headerData;
-
- PIMAGE_DOS_HEADER pDOSHeader;
- PIMAGE_NT_HEADERS pNTHeader;
- PIMAGE_SECTION_HEADER pSectionHeader;
-
- bool validateHeaders();
- bool fillPeHeaderStructs(bool fromDisk);
-
- void fixDump(BYTE * dumpBuffer);
- void fixBadNtHeaderValues(PIMAGE_NT_HEADERS pNtHead);
- void fixSectionHeaderForDump(PIMAGE_SECTION_HEADER oldSecHead, PIMAGE_SECTION_HEADER newSecHead);
- void fixNtHeaderForDump(PIMAGE_NT_HEADERS oldNtHead, PIMAGE_NT_HEADERS newNtHead);
-};
diff --git a/Scylla/PeParser.cpp b/Scylla/PeParser.cpp
index cfba855..a1cbce0 100644
--- a/Scylla/PeParser.cpp
+++ b/Scylla/PeParser.cpp
@@ -1,1162 +1,1220 @@
#include "PeParser.h"
#include "ProcessAccessHelp.h"
#include <algorithm>
+#include <imagehlp.h>
+
+#pragma comment(lib, "Imagehlp.lib")
PeParser::PeParser()
{
initClass();
}
PeParser::PeParser(const WCHAR * file, bool readSectionHeaders)
{
initClass();
filename = file;
if (filename && wcslen(filename) > 3)
{
readPeHeaderFromFile(readSectionHeaders);
if (readSectionHeaders)
{
if (isValidPeFile())
{
getSectionHeaders();
}
}
}
}
PeParser::PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders)
{
initClass();
moduleBaseAddress = moduleBase;
if (moduleBaseAddress)
{
readPeHeaderFromProcess(readSectionHeaders);
if (readSectionHeaders)
{
if (isValidPeFile())
{
getSectionHeaders();
}
}
}
}
PeParser::~PeParser()
{
if (headerMemory)
{
delete [] headerMemory;
}
if (fileMemory)
{
delete [] fileMemory;
}
for (size_t i = 0; i < listPeSection.size(); i++)
{
if (listPeSection[i].data)
{
delete [] listPeSection[i].data;
}
}
listPeSection.clear();
}
void PeParser::initClass()
{
fileMemory = 0;
headerMemory = 0;
pDosHeader = 0;
pDosStub = 0;
dosStubSize = 0;
pNTHeader32 = 0;
pNTHeader64 = 0;
overlayData = 0;
overlaySize = 0;
filename = 0;
fileSize = 0;
moduleBaseAddress = 0;
hFile = INVALID_HANDLE_VALUE;
}
bool PeParser::isPE64()
{
if (isValidPeFile())
{
return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC);
}
else
{
return false;
}
}
bool PeParser::isPE32()
{
if (isValidPeFile())
{
return (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC);
}
else
{
return false;
}
}
bool PeParser::isTargetFileSamePeFormat()
{
#ifdef _WIN64
return isPE64();
#else
return isPE32();
#endif
}
bool PeParser::isValidPeFile()
{
bool retValue = false;
if (pDosHeader)
{
if (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
if (pNTHeader32)
{
if (pNTHeader32->Signature == IMAGE_NT_SIGNATURE)
{
retValue = true;
}
}
}
}
return retValue;
}
bool PeParser::hasDirectory(const int directoryIndex)
{
if (isPE32())
{
return (pNTHeader32->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0);
}
else if (isPE64())
{
return (pNTHeader64->OptionalHeader.DataDirectory[directoryIndex].VirtualAddress != 0);
}
else
{
return false;
}
}
bool PeParser::hasExportDirectory()
{
return hasDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT);
}
bool PeParser::hasTLSDirectory()
{
return hasDirectory(IMAGE_DIRECTORY_ENTRY_TLS);
}
bool PeParser::hasRelocationDirectory()
{
return hasDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC);
}
DWORD PeParser::getEntryPoint()
{
if (isPE32())
{
return pNTHeader32->OptionalHeader.AddressOfEntryPoint;
}
else if (isPE64())
{
return pNTHeader64->OptionalHeader.AddressOfEntryPoint;
}
else
{
return 0;
}
}
bool PeParser::readPeHeaderFromProcess(bool readSectionHeaders)
{
bool retValue = false;
DWORD correctSize = 0;
DWORD readSize = getInitialHeaderReadSize(readSectionHeaders);
headerMemory = new BYTE[readSize];
if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory))
{
retValue = true;
getDosAndNtHeader(headerMemory, (LONG)readSize);
if (isValidPeFile())
{
correctSize = calcCorrectPeHeaderSize(readSectionHeaders);
if (readSize < correctSize)
{
readSize = correctSize;
delete [] headerMemory;
headerMemory = new BYTE[readSize];
if (ProcessAccessHelp::readMemoryPartlyFromProcess(moduleBaseAddress, readSize, headerMemory))
{
getDosAndNtHeader(headerMemory, (LONG)readSize);
}
}
}
}
return retValue;
}
bool PeParser::readPeHeaderFromFile(bool readSectionHeaders)
{
bool retValue = false;
DWORD correctSize = 0;
DWORD numberOfBytesRead = 0;
DWORD readSize = getInitialHeaderReadSize(readSectionHeaders);
headerMemory = new BYTE[readSize];
if (openFileHandle())
{
fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile);
if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0))
{
retValue = true;
getDosAndNtHeader(headerMemory, (LONG)readSize);
if (isValidPeFile())
{
correctSize = calcCorrectPeHeaderSize(readSectionHeaders);
if (readSize < correctSize)
{
readSize = correctSize;
if (fileSize > 0)
{
if (fileSize < correctSize)
{
readSize = fileSize;
}
}
delete [] headerMemory;
headerMemory = new BYTE[readSize];
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
if (ReadFile(hFile, headerMemory, readSize, &numberOfBytesRead, 0))
{
getDosAndNtHeader(headerMemory, (LONG)readSize);
}
}
}
}
closeFileHandle();
}
return retValue;
}
bool PeParser::readPeSectionsFromProcess()
{
bool retValue = true;
DWORD_PTR readOffset = 0;
listPeSection.reserve(getNumberOfSections());
for (WORD i = 0; i < getNumberOfSections(); i++)
{
readOffset = listPeSection[i].sectionHeader.VirtualAddress + moduleBaseAddress;
listPeSection[i].normalSize = listPeSection[i].sectionHeader.Misc.VirtualSize;
if (!readSectionFromProcess(readOffset, listPeSection[i]))
{
retValue = false;
}
}
return retValue;
}
bool PeParser::readPeSectionsFromFile()
{
bool retValue = true;
DWORD readOffset = 0;
listPeSection.reserve(getNumberOfSections());
if (openFileHandle())
{
for (WORD i = 0; i < getNumberOfSections(); i++)
{
readOffset = listPeSection[i].sectionHeader.PointerToRawData;
listPeSection[i].normalSize = listPeSection[i].sectionHeader.SizeOfRawData;
if (!readSectionFromFile(readOffset, listPeSection[i]))
{
retValue = false;
}
}
closeFileHandle();
}
else
{
retValue = false;
}
return retValue;
}
bool PeParser::getSectionHeaders()
{
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader32);
PeFileSection peFileSection;
listPeSection.clear();
listPeSection.reserve(getNumberOfSections());
for (WORD i = 0; i < getNumberOfSections(); i++)
{
memcpy_s(&peFileSection.sectionHeader, sizeof(IMAGE_SECTION_HEADER), pSection, sizeof(IMAGE_SECTION_HEADER));
listPeSection.push_back(peFileSection);
pSection++;
}
return true;
}
bool PeParser::getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen)
{
CHAR sectionNameA[IMAGE_SIZEOF_SHORT_NAME + 1] = {0};
output[0] = 0;
memcpy(sectionNameA, listPeSection[sectionIndex].sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME); //not null terminated
return (swprintf_s(output, outputLen, L"%S", sectionNameA) != -1);
}
WORD PeParser::getNumberOfSections()
{
return pNTHeader32->FileHeader.NumberOfSections;
}
void PeParser::setNumberOfSections(WORD numberOfSections)
{
pNTHeader32->FileHeader.NumberOfSections = numberOfSections;
}
std::vector<PeFileSection> & PeParser::getSectionHeaderList()
{
return listPeSection;
}
void PeParser::getDosAndNtHeader(BYTE * memory, LONG size)
{
pDosHeader = (PIMAGE_DOS_HEADER)memory;
pNTHeader32 = 0;
pNTHeader64 = 0;
dosStubSize = 0;
pDosStub = 0;
if (pDosHeader->e_lfanew > 0 && pDosHeader->e_lfanew < size) //malformed PE
{
pNTHeader32 = (PIMAGE_NT_HEADERS32)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew);
pNTHeader64 = (PIMAGE_NT_HEADERS64)((DWORD_PTR)pDosHeader + pDosHeader->e_lfanew);
if (pDosHeader->e_lfanew > sizeof(IMAGE_DOS_HEADER))
{
dosStubSize = pDosHeader->e_lfanew - sizeof(IMAGE_DOS_HEADER);
pDosStub = (BYTE *)((DWORD_PTR)pDosHeader + sizeof(IMAGE_DOS_HEADER));
}
}
}
DWORD PeParser::calcCorrectPeHeaderSize(bool readSectionHeaders)
{
DWORD correctSize = pDosHeader->e_lfanew + 50; //extra buffer
if (readSectionHeaders)
{
correctSize += getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER);
}
if (isPE32())
{
correctSize += sizeof(IMAGE_NT_HEADERS32);
}
else if(isPE64())
{
correctSize += sizeof(IMAGE_NT_HEADERS64);
}
else
{
correctSize = 0; //not a valid PE
}
return correctSize;
}
DWORD PeParser::getInitialHeaderReadSize(bool readSectionHeaders)
{
DWORD readSize = sizeof(IMAGE_DOS_HEADER) + 200 + sizeof(IMAGE_NT_HEADERS64);
if (readSectionHeaders)
{
readSize += (10 * sizeof(IMAGE_SECTION_HEADER));
}
return readSize;
}
DWORD PeParser::getSectionHeaderBasedFileSize()
{
DWORD lastRawOffset = 0, lastRawSize = 0;
//this is needed if the sections aren't sorted by their RawOffset (e.g. Petite)
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if (listPeSection[i].sectionHeader.PointerToRawData > lastRawOffset)
{
lastRawOffset = listPeSection[i].sectionHeader.PointerToRawData;
lastRawSize = listPeSection[i].sectionHeader.SizeOfRawData;
}
}
return (lastRawSize + lastRawOffset);
}
DWORD PeParser::getSectionHeaderBasedSizeOfImage()
{
DWORD lastVirtualOffset = 0, lastVirtualSize = 0;
//this is needed if the sections aren't sorted by their RawOffset (e.g. Petite)
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if (listPeSection[i].sectionHeader.VirtualAddress > lastVirtualOffset)
{
lastVirtualOffset = listPeSection[i].sectionHeader.VirtualAddress;
lastVirtualSize = listPeSection[i].sectionHeader.Misc.VirtualSize;
}
}
return (lastVirtualSize + lastVirtualOffset);
}
bool PeParser::openFileHandle()
{
if (hFile == INVALID_HANDLE_VALUE)
{
if (filename)
{
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
}
else
{
hFile = INVALID_HANDLE_VALUE;
}
}
return (hFile != INVALID_HANDLE_VALUE);
}
bool PeParser::openWriteFileHandle( const WCHAR * newFile )
{
if (newFile)
{
hFile = CreateFile(newFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
}
else
{
hFile = INVALID_HANDLE_VALUE;
}
return (hFile != INVALID_HANDLE_VALUE);
}
void PeParser::closeFileHandle()
{
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
}
bool PeParser::readSectionFromFile(DWORD readOffset, PeFileSection & peFileSection)
{
const DWORD maxReadSize = 100;
BYTE data[maxReadSize];
DWORD bytesRead = 0;
bool retValue = true;
DWORD valuesFound = 0;
DWORD currentOffset = 0;
DWORD readSize = 0;
peFileSection.data = 0;
peFileSection.dataSize = 0;
readSize = peFileSection.normalSize;
if (!readOffset || !readSize)
{
return true; //section without data is valid
}
if (readSize <= maxReadSize)
{
peFileSection.dataSize = readSize;
peFileSection.normalSize = readSize;
return readPeSectionFromFile(readOffset, peFileSection);
}
currentOffset = readOffset + readSize - maxReadSize;
while(currentOffset >= readOffset) //start from the end
{
SetFilePointer(hFile, currentOffset, 0, FILE_BEGIN);
ZeroMemory(data, sizeof(data));
if (!ReadFile(hFile, data, sizeof(data), &bytesRead, 0))
{
retValue = false;
break;
}
valuesFound = isMemoryNotNull(data, sizeof(data));
if (valuesFound)
{
//found some real code
currentOffset += valuesFound;
if (readOffset < currentOffset)
{
//real size
peFileSection.dataSize = currentOffset - readOffset;
}
break;
}
currentOffset -= maxReadSize;
}
if (peFileSection.dataSize)
{
retValue = readPeSectionFromFile(readOffset, peFileSection);
}
return retValue;
}
DWORD PeParser::isMemoryNotNull( BYTE * data, int dataSize )
{
for (int i = (dataSize - 1); i >= 0; i--)
{
if (data[i] != 0)
{
return i + 1;
}
}
return 0;
}
bool PeParser::savePeFileToDisk( const WCHAR * newFile )
{
bool retValue = true;
DWORD dwFileOffset = 0, dwWriteSize = 0;
if (getNumberOfSections() != listPeSection.size())
{
return false;
}
if (openWriteFileHandle(newFile))
{
//Dos header
dwWriteSize = sizeof(IMAGE_DOS_HEADER);
if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosHeader))
{
retValue = false;
}
dwFileOffset += dwWriteSize;
if (dosStubSize && pDosStub)
{
//Dos Stub
dwWriteSize = dosStubSize;
if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pDosStub))
{
retValue = false;
}
dwFileOffset += dwWriteSize;
}
//Pe Header
if (isPE32())
{
dwWriteSize = sizeof(IMAGE_NT_HEADERS32);
}
else
{
dwWriteSize = sizeof(IMAGE_NT_HEADERS64);
}
if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, pNTHeader32))
{
retValue = false;
}
dwFileOffset += dwWriteSize;
//section headers
dwWriteSize = sizeof(IMAGE_SECTION_HEADER);
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, &listPeSection[i].sectionHeader))
{
retValue = false;
break;
}
dwFileOffset += dwWriteSize;
}
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if (!listPeSection[i].sectionHeader.PointerToRawData)
continue;
if (listPeSection[i].sectionHeader.PointerToRawData > dwFileOffset)
{
dwWriteSize = listPeSection[i].sectionHeader.PointerToRawData - dwFileOffset; //padding
if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize))
{
retValue = false;
break;
}
dwFileOffset += dwWriteSize;
}
dwWriteSize = listPeSection[i].dataSize;
if (dwWriteSize)
{
if (!ProcessAccessHelp::writeMemoryToFile(hFile, listPeSection[i].sectionHeader.PointerToRawData, dwWriteSize, listPeSection[i].data))
{
retValue = false;
break;
}
dwFileOffset += dwWriteSize;
if (listPeSection[i].dataSize < listPeSection[i].sectionHeader.SizeOfRawData) //padding
{
dwWriteSize = listPeSection[i].sectionHeader.SizeOfRawData - listPeSection[i].dataSize;
if (!writeZeroMemoryToFile(hFile, dwFileOffset, dwWriteSize))
{
retValue = false;
break;
}
dwFileOffset += dwWriteSize;
}
}
}
//add overlay?
if (overlaySize && overlayData)
{
dwWriteSize = overlaySize;
if (!ProcessAccessHelp::writeMemoryToFile(hFile, dwFileOffset, dwWriteSize, overlayData))
{
retValue = false;
}
dwFileOffset += dwWriteSize;
}
SetEndOfFile(hFile);
closeFileHandle();
}
return retValue;
}
bool PeParser::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);
}
return retValue;
}
void PeParser::removeDosStub()
{
if (pDosHeader)
{
dosStubSize = 0;
pDosStub = 0; //must not delete []
pDosHeader->e_lfanew = sizeof(IMAGE_DOS_HEADER);
}
}
bool PeParser::readPeSectionFromFile(DWORD readOffset, PeFileSection & peFileSection)
{
DWORD bytesRead = 0;
peFileSection.data = new BYTE[peFileSection.dataSize];
SetFilePointer(hFile, readOffset, 0, FILE_BEGIN);
return (ReadFile(hFile, peFileSection.data, peFileSection.dataSize, &bytesRead, 0) != FALSE);
}
bool PeParser::readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection )
{
const DWORD maxReadSize = 100;
BYTE data[maxReadSize];
bool retValue = true;
DWORD valuesFound = 0;
DWORD readSize = 0;
DWORD_PTR currentOffset = 0;
peFileSection.data = 0;
peFileSection.dataSize = 0;
readSize = peFileSection.normalSize;
if (!readOffset || !readSize)
{
return true; //section without data is valid
}
if (readSize <= maxReadSize)
{
peFileSection.dataSize = readSize;
peFileSection.normalSize = readSize;
return readPeSectionFromProcess(readOffset, peFileSection);
}
currentOffset = readOffset + readSize - maxReadSize;
while(currentOffset >= readOffset) //start from the end
{
if (!ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, sizeof(data), data))
{
retValue = false;
break;
}
valuesFound = isMemoryNotNull(data, sizeof(data));
if (valuesFound)
{
//found some real code
currentOffset += valuesFound;
if (readOffset < currentOffset)
{
//real size
peFileSection.dataSize = (DWORD)(currentOffset - readOffset);
}
break;
}
currentOffset -= maxReadSize;
}
if (peFileSection.dataSize)
{
retValue = readPeSectionFromProcess(readOffset, peFileSection);
}
return retValue;
}
bool PeParser::readPeSectionFromProcess(DWORD_PTR readOffset, PeFileSection & peFileSection)
{
peFileSection.data = new BYTE[peFileSection.dataSize];
return ProcessAccessHelp::readMemoryPartlyFromProcess(readOffset, peFileSection.dataSize, peFileSection.data);
}
DWORD PeParser::alignValue(DWORD badValue, DWORD alignTo)
{
return (((badValue + alignTo - 1) / alignTo) * alignTo);
}
bool PeParser::addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData)
{
size_t nameLength = strlen(sectionName);
DWORD fileAlignment = 0, sectionAlignment = 0;
PeFileSection peFileSection;
if (nameLength > IMAGE_SIZEOF_SHORT_NAME)
{
return false;
}
if (isPE32())
{
fileAlignment = pNTHeader32->OptionalHeader.FileAlignment;
sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment;
}
else
{
fileAlignment = pNTHeader64->OptionalHeader.FileAlignment;
sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment;
}
memcpy_s(peFileSection.sectionHeader.Name, IMAGE_SIZEOF_SHORT_NAME, sectionName, nameLength);
//last section doesn't need SizeOfRawData alignment
peFileSection.sectionHeader.SizeOfRawData = sectionSize; //alignValue(sectionSize, fileAlignment);
peFileSection.sectionHeader.Misc.VirtualSize = alignValue(sectionSize, sectionAlignment);
peFileSection.sectionHeader.PointerToRawData = alignValue(getSectionHeaderBasedFileSize(), fileAlignment);
peFileSection.sectionHeader.VirtualAddress = alignValue(getSectionHeaderBasedSizeOfImage(), sectionAlignment);
peFileSection.sectionHeader.Characteristics = IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA;
peFileSection.normalSize = peFileSection.sectionHeader.SizeOfRawData;
peFileSection.dataSize = peFileSection.sectionHeader.SizeOfRawData;
if (sectionData == 0)
{
peFileSection.data = new BYTE[peFileSection.sectionHeader.SizeOfRawData];
ZeroMemory(peFileSection.data , peFileSection.sectionHeader.SizeOfRawData);
}
else
{
peFileSection.data = sectionData;
}
listPeSection.push_back(peFileSection);
setNumberOfSections(getNumberOfSections() + 1);
return true;
}
DWORD_PTR PeParser::convertRVAToOffsetVector(DWORD_PTR dwRVA)
{
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if ((listPeSection[i].sectionHeader.VirtualAddress <= dwRVA) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > dwRVA))
{
return ((dwRVA - listPeSection[i].sectionHeader.VirtualAddress) + listPeSection[i].sectionHeader.PointerToRawData);
}
}
return 0;
}
DWORD_PTR PeParser::convertOffsetToRVAVector(DWORD_PTR dwOffset)
{
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if ((listPeSection[i].sectionHeader.PointerToRawData <= dwOffset) && ((listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData) > dwOffset))
{
return ((dwOffset - listPeSection[i].sectionHeader.PointerToRawData) + listPeSection[i].sectionHeader.VirtualAddress);
}
}
return 0;
}
void PeParser::fixPeHeader()
{
DWORD dwSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
if (isPE32())
{
//delete bound import directories
pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
//max 16
if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10)
{
pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10;
}
pNTHeader32->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage();
if (moduleBaseAddress)
{
pNTHeader32->OptionalHeader.ImageBase = (DWORD)moduleBaseAddress;
}
pNTHeader32->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader32->OptionalHeader.FileAlignment);
}
else
{
//delete bound import directories
pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
//max 16
if (pNTHeader64->OptionalHeader.NumberOfRvaAndSizes > 0x10)
{
pNTHeader64->OptionalHeader.NumberOfRvaAndSizes = 0x10;
}
pNTHeader64->OptionalHeader.SizeOfImage = getSectionHeaderBasedSizeOfImage();
if (moduleBaseAddress)
{
pNTHeader64->OptionalHeader.ImageBase = moduleBaseAddress;
}
pNTHeader64->OptionalHeader.SizeOfHeaders = alignValue(dwSize + pNTHeader64->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER)), pNTHeader64->OptionalHeader.FileAlignment);
}
removeIatDirectory();
}
void PeParser::removeIatDirectory()
{
DWORD searchAddress = 0;
if (isPE32())
{
searchAddress = pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
pNTHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
else
{
searchAddress = pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = 0;
pNTHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = 0;
}
if (searchAddress)
{
for (WORD i = 0; i < getNumberOfSections(); i++)
{
if ((listPeSection[i].sectionHeader.VirtualAddress <= searchAddress) && ((listPeSection[i].sectionHeader.VirtualAddress + listPeSection[i].sectionHeader.Misc.VirtualSize) > searchAddress))
{
//section must be read and writable
listPeSection[i].sectionHeader.Characteristics |= IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
}
}
}
}
void PeParser::setDefaultFileAlignment()
{
if (isPE32())
{
pNTHeader32->OptionalHeader.FileAlignment = FileAlignmentConstant;
}
else
{
pNTHeader64->OptionalHeader.FileAlignment = FileAlignmentConstant;
}
}
bool PeFileSectionSortByPointerToRawData(const PeFileSection& d1, const PeFileSection& d2)
{
return d1.sectionHeader.PointerToRawData < d2.sectionHeader.PointerToRawData;
}
bool PeFileSectionSortByVirtualAddress(const PeFileSection& d1, const PeFileSection& d2)
{
return d1.sectionHeader.VirtualAddress < d2.sectionHeader.VirtualAddress;
}
void PeParser::alignAllSectionHeaders()
{
DWORD sectionAlignment = 0;
DWORD fileAlignment = 0;
DWORD newFileSize = 0;
if (isPE32())
{
sectionAlignment = pNTHeader32->OptionalHeader.SectionAlignment;
fileAlignment = pNTHeader32->OptionalHeader.FileAlignment;
}
else
{
sectionAlignment = pNTHeader64->OptionalHeader.SectionAlignment;
fileAlignment = pNTHeader64->OptionalHeader.FileAlignment;
}
std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByPointerToRawData); //sort by PointerToRawData ascending
newFileSize = pDosHeader->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNTHeader32->FileHeader.SizeOfOptionalHeader + (getNumberOfSections() * sizeof(IMAGE_SECTION_HEADER));
for (WORD i = 0; i < getNumberOfSections(); i++)
{
listPeSection[i].sectionHeader.VirtualAddress = alignValue(listPeSection[i].sectionHeader.VirtualAddress, sectionAlignment);
listPeSection[i].sectionHeader.Misc.VirtualSize = alignValue(listPeSection[i].sectionHeader.Misc.VirtualSize, sectionAlignment);
listPeSection[i].sectionHeader.PointerToRawData = alignValue(newFileSize, fileAlignment);
listPeSection[i].sectionHeader.SizeOfRawData = alignValue(listPeSection[i].dataSize, fileAlignment);
newFileSize = listPeSection[i].sectionHeader.PointerToRawData + listPeSection[i].sectionHeader.SizeOfRawData;
}
std::sort(listPeSection.begin(), listPeSection.end(), PeFileSectionSortByVirtualAddress); //sort by VirtualAddress ascending
}
bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath)
{
moduleBaseAddress = modBase;
if (readPeSectionsFromProcess())
{
setDefaultFileAlignment();
setEntryPointVa(entryPoint);
alignAllSectionHeaders();
fixPeHeader();
getFileOverlay();
return savePeFileToDisk(dumpFilePath);
}
return false;
}
bool PeParser::dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector<PeSection> & sectionList)
{
if (listPeSection.size() == sectionList.size())
{
for (int i = (getNumberOfSections() - 1); i >= 0; i--)
{
if (!sectionList[i].isDumped)
{
listPeSection.erase(listPeSection.begin() + i);
setNumberOfSections(getNumberOfSections() - 1);
}
else
{
listPeSection[i].sectionHeader.Misc.VirtualSize = sectionList[i].virtualSize;
listPeSection[i].sectionHeader.SizeOfRawData = sectionList[i].rawSize;
listPeSection[i].sectionHeader.Characteristics = sectionList[i].characteristics;
}
}
}
return dumpProcess(modBase, entryPoint, dumpFilePath);
}
void PeParser::setEntryPointVa(DWORD_PTR entryPoint)
{
DWORD entryPointRva = (DWORD)(entryPoint - moduleBaseAddress);
+ setEntryPointRva(entryPointRva);
+}
+
+void PeParser::setEntryPointRva(DWORD entryPoint)
+{
if (isPE32())
{
- pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPointRva;
+ pNTHeader32->OptionalHeader.AddressOfEntryPoint = entryPoint;
}
- else
+ else if (isPE64())
{
- pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPointRva;
+ pNTHeader64->OptionalHeader.AddressOfEntryPoint = entryPoint;
}
-
}
bool PeParser::getFileOverlay()
{
DWORD numberOfBytesRead;
bool retValue = false;
if (!hasOverlayData())
{
return false;
}
if (openFileHandle())
{
DWORD overlayOffset = getSectionHeaderBasedFileSize();
DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(hFile);
overlaySize = fileSize - overlayOffset;
overlayData = new BYTE[overlaySize];
SetFilePointer(hFile, overlayOffset, 0, FILE_BEGIN);
if (ReadFile(hFile, overlayData, overlaySize, &numberOfBytesRead, 0))
{
retValue = true;
}
closeFileHandle();
}
return retValue;
}
bool PeParser::hasOverlayData()
{
if (!filename)
return false;
if (isValidPeFile())
{
DWORD fileSize = (DWORD)ProcessAccessHelp::getFileSize(filename);
return (fileSize > getSectionHeaderBasedFileSize());
}
else
{
return false;
}
}
+bool PeParser::updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize)
+{
+ PIMAGE_NT_HEADERS32 pNTHeader32 = 0;
+ PIMAGE_NT_HEADERS64 pNTHeader64 = 0;
+ DWORD headerSum = 0;
+ DWORD checkSum = 0;
+ bool retValue = false;
+
+ if (!fileSize)
+ return retValue;
+
+ HANDLE hFileToMap = CreateFile(targetFile, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+
+ if(hFileToMap != INVALID_HANDLE_VALUE)
+ {
+ HANDLE hMappedFile = CreateFileMapping(hFileToMap, 0, PAGE_READWRITE, 0, 0, 0);
+ if(hMappedFile)
+ {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ LPVOID addrMappedDll = MapViewOfFile(hMappedFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
+
+ if (addrMappedDll)
+ {
+ pNTHeader32 = (PIMAGE_NT_HEADERS32)CheckSumMappedFile(addrMappedDll, fileSize, &headerSum, &checkSum);
+
+ if (pNTHeader32)
+ {
+ if (pNTHeader32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ {
+ pNTHeader64 = (PIMAGE_NT_HEADERS64)pNTHeader32;
+ pNTHeader64->OptionalHeader.CheckSum = checkSum;
+ }
+ else
+ {
+ pNTHeader32->OptionalHeader.CheckSum = checkSum;
+ }
+
+ retValue = true;
+ }
+
+ UnmapViewOfFile(addrMappedDll);
+ }
+ }
+ CloseHandle(hMappedFile);
+ }
+ CloseHandle(hFileToMap);
+ }
+
+ return retValue;
+}
\ No newline at end of file
diff --git a/Scylla/PeParser.h b/Scylla/PeParser.h
index d0a39f1..687c318 100644
--- a/Scylla/PeParser.h
+++ b/Scylla/PeParser.h
@@ -1,127 +1,131 @@
#pragma once
#include <windows.h>
#include <vector>
#include "DumpSectionGui.h"
class PeFileSection {
public:
IMAGE_SECTION_HEADER sectionHeader;
BYTE * data;
DWORD dataSize;
DWORD normalSize;
PeFileSection()
{
ZeroMemory(§ionHeader, sizeof(IMAGE_SECTION_HEADER));
data = 0;
dataSize = 0;
normalSize = 0;
}
};
class PeParser
{
public:
PeParser(const WCHAR * file, bool readSectionHeaders = true);
PeParser(const DWORD_PTR moduleBase, bool readSectionHeaders = true);
~PeParser();
bool isValidPeFile();
bool isPE64();
bool isPE32();
bool isTargetFileSamePeFormat();
WORD getNumberOfSections();
std::vector<PeFileSection> & getSectionHeaderList();
bool hasExportDirectory();
bool hasTLSDirectory();
bool hasRelocationDirectory();
bool hasOverlayData();
DWORD getEntryPoint();
bool getSectionNameUnicode(const int sectionIndex, WCHAR * output, const int outputLen);
DWORD getSectionHeaderBasedFileSize();
DWORD getSectionHeaderBasedSizeOfImage();
bool readPeSectionsFromProcess();
bool readPeSectionsFromFile();
bool savePeFileToDisk(const WCHAR * newFile);
void removeDosStub();
void alignAllSectionHeaders();
void fixPeHeader();
void setDefaultFileAlignment();
bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath);
bool dumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR * dumpFilePath, std::vector<PeSection> & sectionList);
+
+ void setEntryPointVa(DWORD_PTR entryPoint);
+ void setEntryPointRva(DWORD entryPoint);
+
+ static bool updatePeHeaderChecksum(const WCHAR * targetFile, DWORD fileSize);
protected:
PeParser();
static const DWORD FileAlignmentConstant = 0x200;
const WCHAR * filename;
DWORD_PTR moduleBaseAddress;
/************************************************************************/
/* PE FILE */
/* */
/* IMAGE_DOS_HEADER 64 0x40 */
/* IMAGE_NT_HEADERS32 248 0xF8 */
/* IMAGE_NT_HEADERS64 264 0x108 */
/* IMAGE_SECTION_HEADER 40 0x28 */
/************************************************************************/
PIMAGE_DOS_HEADER pDosHeader;
BYTE * pDosStub; //between dos header and section header
DWORD dosStubSize;
PIMAGE_NT_HEADERS32 pNTHeader32;
PIMAGE_NT_HEADERS64 pNTHeader64;
std::vector<PeFileSection> listPeSection;
BYTE * overlayData;
DWORD overlaySize;
/************************************************************************/
BYTE * fileMemory;
BYTE * headerMemory;
HANDLE hFile;
DWORD fileSize;
bool readPeHeaderFromFile(bool readSectionHeaders);
bool readPeHeaderFromProcess(bool readSectionHeaders);
bool hasDirectory(const int directoryIndex);
bool getSectionHeaders();
void getDosAndNtHeader(BYTE * memory, LONG size);
DWORD calcCorrectPeHeaderSize( bool readSectionHeaders );
DWORD getInitialHeaderReadSize( bool readSectionHeaders );
bool openFileHandle();
void closeFileHandle();
void initClass();
DWORD isMemoryNotNull( BYTE * data, int dataSize );
bool openWriteFileHandle( const WCHAR * newFile );
bool writeZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size);
bool readPeSectionFromFile( DWORD readOffset, PeFileSection & peFileSection );
bool readPeSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection );
bool readSectionFromFile( DWORD readOffset, PeFileSection & peFileSection );
bool readSectionFromProcess( DWORD_PTR readOffset, PeFileSection & peFileSection );
bool addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData);
DWORD alignValue(DWORD badValue, DWORD alignTo);
DWORD_PTR convertOffsetToRVAVector(DWORD_PTR dwOffset);
DWORD_PTR convertRVAToOffsetVector(DWORD_PTR dwRVA);
void setNumberOfSections(WORD numberOfSections);
void removeIatDirectory();
- void setEntryPointVa( DWORD_PTR entryPoint );
bool getFileOverlay();
};
diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h
index 5478853..0da536d 100644
--- a/Scylla/Scylla.h
+++ b/Scylla/Scylla.h
@@ -1,31 +1,31 @@
#pragma once
#include "ConfigurationHolder.h"
#include "PluginLoader.h"
#include "ProcessLister.h"
#include "Logger.h"
#define APPNAME_S "Scylla"
-#define APPVERSION_S "v0.6a"
+#define APPVERSION_S "v0.6b"
#define APPNAME TEXT(APPNAME_S)
#define APPVERSION TEXT(APPVERSION_S)
class Scylla
{
public:
static void init();
static ConfigurationHolder config;
static PluginLoader plugins;
static ProcessLister processLister;
static FileLog debugLog;
static ListboxLog windowLog;
private:
static const WCHAR DEBUG_LOG_FILENAME[];
};
diff --git a/Scylla/Scylla.vcxproj b/Scylla/Scylla.vcxproj
index 8397a2f..f533d27 100644
--- a/Scylla/Scylla.vcxproj
+++ b/Scylla/Scylla.vcxproj
@@ -1,252 +1,248 @@
<?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>
<PlatformToolset>v90</PlatformToolset>
</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>v90</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>
<IncludePath>$(SolutionDir)WTL81_9127_Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)WTL81_9127_Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<IncludePath>$(SolutionDir)WTL81_9127_Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)WTL81_9127_Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)tinyxml;$(SolutionDir)diStorm\include;%(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>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(TargetDir)$(TargetName).map</MapFileName>
</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)tinyxml;$(SolutionDir)diStorm\include;%(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)tinyxml;$(SolutionDir)diStorm\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MinimalRebuild>true</MinimalRebuild>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</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)tinyxml;$(SolutionDir)diStorm\include;%(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="DeviceNameResolver.cpp" />
<ClCompile Include="DisassemblerGui.cpp" />
<ClCompile Include="DllInjection.cpp" />
<ClCompile Include="DllInjectionPlugin.cpp" />
<ClCompile Include="DumpMemoryGui.cpp" />
<ClCompile Include="DumpSectionGui.cpp" />
<ClCompile Include="IATSearch.cpp" />
- <ClCompile Include="ImportRebuild.cpp" />
+ <ClCompile Include="ImportRebuilder.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="PeParser.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="StringConversion.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="DeviceNameResolver.h" />
<ClInclude Include="DisassemblerGui.h" />
<ClInclude Include="DllInjection.h" />
<ClInclude Include="DllInjectionPlugin.h" />
<ClInclude Include="DumpMemoryGui.h" />
<ClInclude Include="DumpSectionGui.h" />
<ClInclude Include="hexedit.h" />
<ClInclude Include="IATSearch.h" />
- <ClInclude Include="ImportRebuild.h" />
+ <ClInclude Include="ImportRebuilder.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="PeParser.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="StringConversion.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/resource.h b/Scylla/resource.h
index 2072e6a..9ecb538 100644
Binary files a/Scylla/resource.h and b/Scylla/resource.h differ
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, May 27, 9:19 AM (1 d, 14 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
b8/f1/44b2a0c73a5a79cfce57fad22129
Attached To
rSCY Scylla
Event Timeline
Log In to Comment