diff --git a/Scylla/DisassemblerGui.cpp b/Scylla/DisassemblerGui.cpp
index 4b9257b..1365699 100644
--- a/Scylla/DisassemblerGui.cpp
+++ b/Scylla/DisassemblerGui.cpp
@@ -1,385 +1,481 @@
 #include "DisassemblerGui.h"
-
+#include <algorithm>
 #include "ProcessAccessHelp.h"
 #include "Architecture.h"
+#include <Psapi.h>
+#pragma comment(lib, "Psapi.lib")
 
-DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress)
+DisassemblerGui::DisassemblerGui(DWORD_PTR startAddress, ApiReader * apiReaderObject)
 {
+	apiReader = apiReaderObject;
 	addressHistoryIndex = 0;
 	addressHistory.push_back(startAddress);
 	hMenuDisassembler.LoadMenu(IDR_MENU_DISASSEMBLER);
+
+	initAddressCommentList();
 }
 
 BOOL DisassemblerGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
 {
 	DoDataExchange(); // attach controls
 	DlgResize_Init(true, true);
 
 	addColumnsToDisassembler(ListDisassembler);
 	displayDisassembly();
 
 	EditAddress.SetValue(addressHistory[addressHistoryIndex]);
 
 	CenterWindow();
 
 	return TRUE;
 }
 
 void DisassemblerGui::OnContextMenu(CWindow wnd, CPoint point)
 {
 	if (wnd.GetDlgCtrlID() == IDC_LIST_DISASSEMBLER)
 	{
 		int selection = ListDisassembler.GetSelectionMark();
 		if(selection == -1) // no item selected
 			return;
 
 		if(point.x == -1 && point.y == -1) // invoked by keyboard
 		{
 			ListDisassembler.EnsureVisible(selection, TRUE);
 			ListDisassembler.GetItemPosition(selection, &point);
 			ListDisassembler.ClientToScreen(&point);
 		}
 
 		CMenuHandle hSub = hMenuDisassembler.GetSubMenu(0);
 		BOOL menuItem = hSub.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, wnd);
 		if (menuItem)
 		{
 			int column = -1;
 			switch (menuItem)
 			{
 			case ID__DIS_ADDRESS:
 				column = COL_ADDRESS;
 				break;
 			case ID__DIS_SIZE:
 				column = COL_INSTRUCTION_SIZE;
 				break;
 			case ID__DIS_OPCODES:
 				column = COL_OPCODES;
 				break;
 			case ID__DIS_INSTRUCTIONS:
 				column = COL_INSTRUCTION;
 				break;
 			case ID__DIS_FOLLOW:
 				followInstruction(selection);
 				break;
 			case ID__DIS_DISASSEMBLEHERE:
 				{
 					disassembleNewAddress((DWORD_PTR)ProcessAccessHelp::decomposerResult[selection].addr);
 				}
 				
 			}
 			if(column != -1)
 			{
 				tempBuffer[0] = '\0';
 				ListDisassembler.GetItemText(selection, column, tempBuffer, _countof(tempBuffer));
 				copyToClipboard(tempBuffer);
 			}
 		}
 	}
 }
 
 LRESULT DisassemblerGui::OnNMCustomdraw(NMHDR* pnmh)
 {
 	LRESULT pResult = 0;
 	LPNMLVCUSTOMDRAW lpLVCustomDraw = (LPNMLVCUSTOMDRAW)(pnmh);
 	DWORD_PTR itemIndex = 0;
 
 	switch(lpLVCustomDraw->nmcd.dwDrawStage)
 	{
 	case CDDS_ITEMPREPAINT:
 	case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
 		{
 			itemIndex = lpLVCustomDraw->nmcd.dwItemSpec;
 
 			if (lpLVCustomDraw->iSubItem == COL_INSTRUCTION)
 			{
 					doColorInstruction(lpLVCustomDraw, itemIndex);
 			}
 			else 
 			{
 				lpLVCustomDraw->clrText = CLR_DEFAULT;
 				lpLVCustomDraw->clrTextBk = CLR_DEFAULT;
 			}
 		}
 		break;
 	}
 
 
 	pResult |= CDRF_NOTIFYPOSTPAINT;
 	pResult |= CDRF_NOTIFYITEMDRAW;
 	pResult |= CDRF_NOTIFYSUBITEMDRAW;
 
 	return pResult;
 }
 
 void DisassemblerGui::OnExit(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	EndDialog(0);
 }
 
 void DisassemblerGui::OnDisassemble(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	DWORD_PTR address = EditAddress.GetValue();
 	if (address)
 	{
 		disassembleNewAddress(address);
 	}
 }
 
 void DisassemblerGui::disassembleNewAddress(DWORD_PTR address)
 {
 	if (addressHistory[addressHistory.size() - 1] != address)
 	{
 		addressHistory.push_back(address);
 		addressHistoryIndex = (int)addressHistory.size() - 1;
 		EditAddress.SetValue(addressHistory[addressHistoryIndex]);
 
 		if (!displayDisassembly())
 		{
 			MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR);
 		}
 	}
 
 }
 
 void DisassemblerGui::OnDisassembleForward(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	if (addressHistoryIndex != (addressHistory.size() - 1))
 	{
 		addressHistoryIndex++;
 		EditAddress.SetValue(addressHistory[addressHistoryIndex]);
 		if (!displayDisassembly())
 		{
 			MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR);
 		}
 	}
 }
 
 void DisassemblerGui::OnDisassembleBack(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	if (addressHistoryIndex != 0)
 	{
 		addressHistoryIndex--;
 		EditAddress.SetValue(addressHistory[addressHistoryIndex]);
 		if (!displayDisassembly())
 		{
 			MessageBox(L"Cannot disassemble memory at this address",L"Error",MB_ICONERROR);
 		}
 	}
 }
 
 void DisassemblerGui::addColumnsToDisassembler(CListViewCtrl& list)
 {
 	list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
 
 	list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_LEFT);
 	list.InsertColumn(COL_INSTRUCTION_SIZE, L"Size", LVCFMT_CENTER);
 	list.InsertColumn(COL_OPCODES, L"Opcodes", LVCFMT_LEFT);
 	list.InsertColumn(COL_INSTRUCTION, L"Instructions", LVCFMT_LEFT);
 	list.InsertColumn(COL_COMMENT, L"Comment", LVCFMT_LEFT);
 }
 
 bool DisassemblerGui::displayDisassembly()
 {
 	ListDisassembler.DeleteAllItems();
 
 	if(!ProcessAccessHelp::readMemoryFromProcess(addressHistory[addressHistoryIndex], sizeof(data), data))
 		return false;
 
 	if (!ProcessAccessHelp::decomposeMemory(data, sizeof(data), addressHistory[addressHistoryIndex]))
 		return false;
 
 	if (!ProcessAccessHelp::disassembleMemory(data, sizeof(data), addressHistory[addressHistoryIndex]))
 		return false;
 
 	for (unsigned int i = 0; i < ProcessAccessHelp::decodedInstructionsCount; i++)
 	{
 		swprintf_s(tempBuffer, PRINTF_DWORD_PTR_FULL,ProcessAccessHelp::decodedInstructions[i].offset);
 
 		ListDisassembler.InsertItem(i, tempBuffer);
 
 		swprintf_s(tempBuffer, L"%02d",ProcessAccessHelp::decodedInstructions[i].size);
 
 		ListDisassembler.SetItemText(i, COL_INSTRUCTION_SIZE, tempBuffer);
 
 		swprintf_s(tempBuffer, L"%S", (char *)ProcessAccessHelp::decodedInstructions[i].instructionHex.p);
 
 		toUpperCase(tempBuffer);
 		ListDisassembler.SetItemText(i, COL_OPCODES, tempBuffer);
 
 		swprintf_s(tempBuffer, L"%S%S%S",(char*)ProcessAccessHelp::decodedInstructions[i].mnemonic.p, ProcessAccessHelp::decodedInstructions[i].operands.length != 0 ? " " : "", (char*)ProcessAccessHelp::decodedInstructions[i].operands.p);
 
 		toUpperCase(tempBuffer);
 		ListDisassembler.SetItemText(i, COL_INSTRUCTION, tempBuffer);
 
 		tempBuffer[0] = 0;
 		if (getDisassemblyComment(i))
 		{
 			ListDisassembler.SetItemText(i, COL_COMMENT, tempBuffer);
 		}
 	}
 
 	ListDisassembler.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER);
 	ListDisassembler.SetColumnWidth(COL_INSTRUCTION_SIZE, LVSCW_AUTOSIZE_USEHEADER);
 	ListDisassembler.SetColumnWidth(COL_OPCODES, 140);
 	ListDisassembler.SetColumnWidth(COL_INSTRUCTION, LVSCW_AUTOSIZE_USEHEADER);
 	ListDisassembler.SetColumnWidth(COL_COMMENT, LVSCW_AUTOSIZE_USEHEADER);
 
 	return true;
 }
 
 void DisassemblerGui::copyToClipboard(const WCHAR * text)
 {
 	if(OpenClipboard())
 	{
 		EmptyClipboard();
 		size_t len = wcslen(text);
 		HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(WCHAR));
 		if(hMem)
 		{
 			wcscpy_s(static_cast<WCHAR *>(GlobalLock(hMem)), len + 1, text);
 			GlobalUnlock(hMem);
 			if(!SetClipboardData(CF_UNICODETEXT, hMem))
 			{
 				GlobalFree(hMem);
 			}
 		}
 		CloseClipboard();
 	}
 }
 
 void DisassemblerGui::toUpperCase(WCHAR * lowercase)
 {
 	for (size_t i = 0; i < wcslen(lowercase); i++)
 	{
 		if (lowercase[i] != L'x')
 		{
 			lowercase[i] = towupper(lowercase[i]);
 		}
 	}
 }
 
 void DisassemblerGui::doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex )
 {
 	if (ProcessAccessHelp::decomposerResult[itemIndex].flags == FLAG_NOT_DECODABLE)
 	{
 		lpLVCustomDraw->clrText = RGB(255,255,255); // white text
 		lpLVCustomDraw->clrTextBk = RGB(255,0,0); // red background
 	}
 	else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_RET)
 	{
 		lpLVCustomDraw->clrTextBk = RGB(0,255,255); // aqua
 	}
 	else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_CALL)
 	{
 		lpLVCustomDraw->clrTextBk = RGB(255,255,0); // yellow
 	}
 	else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_UNC_BRANCH)
 	{
 		lpLVCustomDraw->clrTextBk = RGB(0x32,0xCD,0x32); // limegreen
 	}
 	else if (META_GET_FC(ProcessAccessHelp::decomposerResult[itemIndex].meta) == FC_CND_BRANCH)
 	{
 		lpLVCustomDraw->clrTextBk = RGB(0xAD,0xFF,0x2F); // greenyellow
 	}
 
 }
 
 void DisassemblerGui::followInstruction(int index)
 {
 	DWORD_PTR address = 0;
 	DWORD_PTR addressTemp = 0;
 	DWORD type = META_GET_FC(ProcessAccessHelp::decomposerResult[index].meta);
 
 	if (ProcessAccessHelp::decomposerResult[index].flags != FLAG_NOT_DECODABLE)
 	{
 		if (type == FC_CALL || type == FC_UNC_BRANCH || type == FC_CND_BRANCH)
 		{
 #ifdef _WIN64
 			if (ProcessAccessHelp::decomposerResult[index].flags & FLAG_RIP_RELATIVE)
 			{
 				addressTemp = INSTRUCTION_GET_RIP_TARGET(&ProcessAccessHelp::decomposerResult[index]);
 
 				if(!ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address))
 				{
 					address = 0;
 				}
 			}
 #endif
 
 			if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC)
 			{
 				address = (DWORD_PTR)INSTRUCTION_GET_TARGET(&ProcessAccessHelp::decomposerResult[index]);
 			}
 
 			if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_DISP)
 			{
 				addressTemp = (DWORD_PTR)ProcessAccessHelp::decomposerResult[index].disp;
 
 				if(!ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address))
 				{
 					address = 0;
 				}
 			}
 
 			if (address != 0)
 			{
 				disassembleNewAddress(address);
 			}
 		}
 
 	}
 }
 
 bool DisassemblerGui::getDisassemblyComment(unsigned int index)
 {
 	DWORD_PTR address = 0;
 	DWORD_PTR addressTemp = 0;
 	DWORD type = META_GET_FC(ProcessAccessHelp::decomposerResult[index].meta);
 
 	tempBuffer[0] = 0;
 
 	if (ProcessAccessHelp::decomposerResult[index].flags != FLAG_NOT_DECODABLE)
 	{
 		if (type == FC_CALL || type == FC_UNC_BRANCH || type == FC_CND_BRANCH)
 		{
-#ifdef _WIN64
 			if (ProcessAccessHelp::decomposerResult[index].flags & FLAG_RIP_RELATIVE)
 			{
+				#ifdef _WIN64
 				addressTemp = (DWORD_PTR)INSTRUCTION_GET_RIP_TARGET(&ProcessAccessHelp::decomposerResult[index]);
 
 				swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,addressTemp);
 
 				if(ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address))
 				{
 					swprintf_s(tempBuffer,L"%s -> "PRINTF_DWORD_PTR_FULL,tempBuffer,address);
-					return true;
 				}
+				#endif
 			}
-#endif
-
-			if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC)
+			else if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_PC)
 			{
 				address = (DWORD_PTR)INSTRUCTION_GET_TARGET(&ProcessAccessHelp::decomposerResult[index]);
 				swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,address);
-				return true;
 			}
-
-			if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_DISP)
+			else if (ProcessAccessHelp::decomposerResult[index].ops[0].type == O_DISP)
 			{
 				addressTemp = (DWORD_PTR)ProcessAccessHelp::decomposerResult[index].disp;
 
 				swprintf_s(tempBuffer,L"-> "PRINTF_DWORD_PTR_FULL,addressTemp);
 
+				address = 0;
 				if(ProcessAccessHelp::readMemoryFromProcess(addressTemp, sizeof(DWORD_PTR), &address))
 				{
 					swprintf_s(tempBuffer,L"%s -> "PRINTF_DWORD_PTR_FULL,tempBuffer,address);
-					return true;
 				}
 			}
 		}
+	}
+
+	if (address != 0)
+	{
+		analyzeAddress(address, tempBuffer);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void DisassemblerGui::initAddressCommentList()
+{
+	HMODULE * hMods = 0;
+	HMODULE hModResult = 0;
+	WCHAR target[MAX_PATH];
+
+	DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(ProcessAccessHelp::hProcess, &hMods);
+	if (numHandles == 0)
+	{
+		return;
+	}
+
+	for (DWORD i = 0; i < numHandles; i++)
+	{
+		if (ProcessAccessHelp::targetImageBase != (DWORD_PTR)hMods[i])
+		{
+			if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target)))
+			{
+				addModuleAddressCommentEntry((DWORD_PTR)hMods[i], (DWORD)ProcessAccessHelp::getSizeOfImageProcess(ProcessAccessHelp::hProcess, (DWORD_PTR)hMods[i]), target);
+			}
+			else
+			{
+#ifdef DEBUG_COMMENTS
+				Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError());
+#endif
+			}
+		}
+	}
+
+	std::sort(addressCommentList.begin(), addressCommentList.end());
+}
 
+void DisassemblerGui::addModuleAddressCommentEntry( DWORD_PTR address, DWORD moduleSize, const WCHAR * modulePath )
+{
+	DisassemblerAddressComment commentObj;
+	//get filename
+	const WCHAR* slash = wcsrchr(modulePath, L'\\');
+	if(slash)
+	{
+		modulePath = slash+1;
 	}
 
-	return false;
+	wcscpy_s(commentObj.comment, _countof(commentObj.comment), modulePath);
+	commentObj.address = address;
+	commentObj.type = ADDRESS_TYPE_MODULE;
+	commentObj.moduleSize = moduleSize;
+
+	addressCommentList.push_back(commentObj);
+}
+
+void DisassemblerGui::analyzeAddress( DWORD_PTR address, WCHAR * comment )
+{
+	if (addressCommentList[0].address > address) //list is sorted, TODO: binary search
+	{
+		return;
+	}
+	bool isSuspect;
+	ApiInfo * api = apiReader->getApiByVirtualAddress(address, &isSuspect);
+
+	if (api != 0 && api != (ApiInfo *)1)
+	{
+		if (api->name[0] == 0)
+		{
+			swprintf_s(tempBuffer,L"%s = %s.%04X", comment, api->module->getFilename(), api->ordinal);
+		}
+		else
+		{
+			swprintf_s(tempBuffer,L"%s = %s.%S", comment, api->module->getFilename(), api->name);
+		}
+	}
+	else
+	{
+		for (size_t i = 0; i < addressCommentList.size(); i++) 
+		{
+			if (addressCommentList[i].type == ADDRESS_TYPE_MODULE)
+			{
+				if (address >= addressCommentList[i].address && address < (addressCommentList[i].address + addressCommentList[i].moduleSize))
+				{
+					swprintf_s(tempBuffer,L"%s = %s", comment, addressCommentList[i].comment);
+					return;
+				}
+			}
+		}
+	}
+
+
 }
diff --git a/Scylla/DisassemblerGui.h b/Scylla/DisassemblerGui.h
index a789605..17bd15e 100644
--- a/Scylla/DisassemblerGui.h
+++ b/Scylla/DisassemblerGui.h
@@ -1,111 +1,134 @@
 #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 like CString
 #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"
 
+#include "ApiReader.h"
+
+enum DisassemblerAddressType {
+	ADDRESS_TYPE_MODULE,
+	ADDRESS_TYPE_API,
+	ADDRESS_TYPE_SPECIAL
+};
+
+class DisassemblerAddressComment
+{
+public:
+	DWORD_PTR address;
+	WCHAR comment[MAX_PATH];
+	DisassemblerAddressType type;
+	DWORD moduleSize;
+
+	bool operator<(DisassemblerAddressComment rhs) { return address < rhs.address; }
+};
+
 class DisassemblerGui : public CDialogImpl<DisassemblerGui>, public CWinDataExchange<DisassemblerGui>, public CDialogResize<DisassemblerGui>
 {
 public:
 	enum { IDD = IDD_DLG_DISASSEMBLER };
 
 	BEGIN_DDX_MAP(DisassemblerGui)
 		DDX_CONTROL_HANDLE(IDC_LIST_DISASSEMBLER, ListDisassembler)
 		DDX_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE, EditAddress)
 	END_DDX_MAP()
 
 	BEGIN_MSG_MAP(DisassemblerGui)
 		MSG_WM_INITDIALOG(OnInitDialog)
 		MSG_WM_CONTEXTMENU(OnContextMenu)
 
 		NOTIFY_HANDLER_EX(IDC_LIST_DISASSEMBLER, NM_CUSTOMDRAW, OnNMCustomdraw)
 
 		COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLE, OnDisassemble)
 		COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_BACK, OnDisassembleBack)
 		COMMAND_ID_HANDLER_EX(IDC_BUTTON_DISASSEMBLER_FORWARD, OnDisassembleForward)
 		COMMAND_ID_HANDLER_EX(IDCANCEL, OnExit)
 		COMMAND_ID_HANDLER_EX(IDOK, OnExit)
 
 		CHAIN_MSG_MAP(CDialogResize<DisassemblerGui>)
 	END_MSG_MAP()
 
 	BEGIN_DLGRESIZE_MAP(DisassemblerGui)
 		DLGRESIZE_CONTROL(IDC_LIST_DISASSEMBLER,     DLSZ_SIZE_X | DLSZ_SIZE_Y)
 		DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLE,     DLSZ_MOVE_X | DLSZ_MOVE_Y)
 		DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_BACK,     DLSZ_MOVE_X | DLSZ_MOVE_Y)
 		DLGRESIZE_CONTROL(IDC_BUTTON_DISASSEMBLER_FORWARD,     DLSZ_MOVE_X | DLSZ_MOVE_Y)
 		DLGRESIZE_CONTROL(IDC_EDIT_ADDRESS_DISASSEMBLE,   DLSZ_MOVE_Y)
 		DLGRESIZE_CONTROL(IDC_STATIC_ADDRESS_DISASSEMBLE,   DLSZ_MOVE_Y)
 	END_DLGRESIZE_MAP()
 
-	DisassemblerGui(DWORD_PTR startAddress);
+	DisassemblerGui(DWORD_PTR startAddress, ApiReader * apiReaderObject);
 
 protected:
 
 	// Variables
 
 	static const size_t DISASSEMBLER_GUI_MEMORY_SIZE = 0x120;
 
 	WCHAR tempBuffer[100];
 	int addressHistoryIndex;
 
 	std::vector<DWORD_PTR> addressHistory;
 
+	std::vector<DisassemblerAddressComment> addressCommentList;
+
 	// Controls
 
 	CListViewCtrl ListDisassembler;
 	CHexEdit<DWORD_PTR> EditAddress;
 
 	enum DisassemblerColumns {
 		COL_ADDRESS = 0,
 		COL_INSTRUCTION_SIZE,
 		COL_OPCODES,
 		COL_INSTRUCTION,
 		COL_COMMENT
 	};
 
 	// Handles
 
 	CMenu hMenuDisassembler;
 
-protected:
-
 	// Message handlers
 
 	BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam);
 	void OnContextMenu(CWindow wnd, CPoint point);
 	void OnExit(UINT uNotifyCode, int nID, CWindow wndCtl);
 	LRESULT OnNMCustomdraw(NMHDR* pnmh);
 	void OnDisassemble(UINT uNotifyCode, int nID, CWindow wndCtl);
 	void OnDisassembleBack(UINT uNotifyCode, int nID, CWindow wndCtl);
 	void OnDisassembleForward(UINT uNotifyCode, int nID, CWindow wndCtl);
 	// GUI functions
 
 	void addColumnsToDisassembler(CListViewCtrl& list);
 	bool displayDisassembly();
 
 	// Misc
 
 	void copyToClipboard(const WCHAR * text);
 
 private:
+	ApiReader * apiReader;
 	BYTE data[DISASSEMBLER_GUI_MEMORY_SIZE];
 
 	void toUpperCase(WCHAR * lowercase);
 	void doColorInstruction( LPNMLVCUSTOMDRAW lpLVCustomDraw, DWORD_PTR itemIndex );
 	void followInstruction(int index);
 	bool getDisassemblyComment(unsigned int index);
 
 	void disassembleNewAddress(DWORD_PTR address);
+	void initAddressCommentList();
+	void addModuleAddressCommentEntry( DWORD_PTR address, DWORD moduleSize, const WCHAR * modulePath );
+	void analyzeAddress( DWORD_PTR address, WCHAR * comment );
 };
diff --git a/Scylla/DllInjection.cpp b/Scylla/DllInjection.cpp
index c8f5fed..422d97c 100644
--- a/Scylla/DllInjection.cpp
+++ b/Scylla/DllInjection.cpp
@@ -1,246 +1,225 @@
 #include "DllInjection.h"
 #include <Psapi.h>
 #include "Scylla.h"
 
 #include "NativeWinApi.h"
+#include "ProcessAccessHelp.h"
+
+#pragma comment(lib, "Psapi.lib")
 
 //#define DEBUG_COMMENTS
 
 	HMODULE DllInjection::dllInjection(HANDLE hProcess, const WCHAR * filename)
 	{
 		LPVOID remoteMemory = 0;
 		SIZE_T memorySize = 0;
 		HANDLE hThread = 0;
 		HMODULE hModule = 0;
 
 		memorySize = (wcslen(filename) + 1) * sizeof(WCHAR);
 
 		if (memorySize < 7)
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"dllInjection :: memorySize invalid");
 #endif
 			return 0;
 		}
 
 		remoteMemory = VirtualAllocEx(hProcess, NULL, memorySize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
 		if (remoteMemory == 0)
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"dllInjection :: VirtualAllocEx failed 0x%X", GetLastError());
 #endif
 			return 0;
 		}
 
 		if (WriteProcessMemory(hProcess, remoteMemory, filename, memorySize, &memorySize))
 		{
 			hThread = startRemoteThread(hProcess,LoadLibraryW,remoteMemory);
 
 			if (hThread)
 			{
 				WaitForSingleObject(hThread, INFINITE);
 
 #ifdef _WIN64
 
 				hModule = getModuleHandleByFilename(hProcess, filename);
 
 #else
 				//returns only 32 bit values -> design bug by microsoft
 				if (!GetExitCodeThread(hThread, (LPDWORD) &hModule))
 				{
 #ifdef DEBUG_COMMENTS
 					Scylla::debugLog.log(L"dllInjection :: GetExitCodeThread failed 0x%X", GetLastError());
 #endif
 					hModule = 0;
 				}
 #endif
 
 				CloseHandle(hThread);
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"dllInjection :: CreateRemoteThread failed 0x%X", GetLastError());
 #endif
 			}
 		}
 		else
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"dllInjection :: WriteProcessMemory failed 0x%X", GetLastError());
 #endif
 		}
 
 
 		VirtualFreeEx(hProcess, remoteMemory, 0, MEM_RELEASE);
 
 		return hModule;
 	}
 
 	bool DllInjection::unloadDllInProcess(HANDLE hProcess, HMODULE hModule)
 	{
 		HANDLE hThread = 0;
 		DWORD lpThreadId = 0;
 		BOOL freeLibraryRet = 0;
 
 		
 		hThread = startRemoteThread(hProcess,FreeLibrary,hModule);
 
 		if (hThread)
 		{
 			WaitForSingleObject(hThread, INFINITE);
 
 			if (!GetExitCodeThread(hThread, (LPDWORD) &freeLibraryRet))
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"unloadDllInProcess :: GetExitCodeThread failed 0x%X", GetLastError());
 #endif
 				freeLibraryRet = 0;
 			}
 
 			CloseHandle(hThread);
 		}
 		else
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"unloadDllInProcess :: CreateRemoteThread failed 0x%X", GetLastError());
 #endif
 		}
 
 		return freeLibraryRet != 0;
 	}
 
 	HMODULE DllInjection::getModuleHandleByFilename( HANDLE hProcess, const WCHAR * filename )
 	{
 		HMODULE * hMods = 0;
 		HMODULE hModResult = 0;
-		DWORD count = 0;
 		WCHAR target[MAX_PATH];
-		DWORD cbNeeded = 0;
-		bool notEnough = true;
-
-		count = 100;
-		hMods = new HMODULE[count];
 
-		do 
+		DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(hProcess, &hMods);
+		if (numHandles == 0)
 		{
-			if (!EnumProcessModules(hProcess, hMods, count * sizeof(HMODULE), &cbNeeded))
-			{
-#ifdef DEBUG_COMMENTS
-				Scylla::debugLog.log(L"DllInjection::getModuleHandle :: EnumProcessModules failed count %d", count);
-#endif
-				delete [] hMods;
-				return 0;
-			}
-
-			if ( (count * sizeof(HMODULE)) < cbNeeded )
-			{
-				delete [] hMods;
-				count += 100;
-				hMods = new HMODULE[count];
-			}
-			else
-			{
-				notEnough = false;
-			}
-		} while (notEnough);
-
+			return 0;
+		}
 
-		for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
+		for (DWORD i = 0; i < numHandles; i++)
 		{
 			if (GetModuleFileNameExW(hProcess, hMods[i], target, _countof(target)))
 			{
-				if (!_wcsicmp(target,filename))
+				if (!_wcsicmp(target, filename))
 				{
 					hModResult = hMods[i];
 					break;
 				}
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"DllInjection::getModuleHandle :: GetModuleFileNameExW failed 0x%X", GetLastError());
 #endif
 			}
 		}
 
 		if (!hModResult)
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"DllInjection::getModuleHandle :: Handle not found");
 #endif
 		}
 
 		delete [] hMods;
 
 		return hModResult;
 	}
 
 	void DllInjection::specialThreadSettings( HANDLE hThread )
 	{
 		if (hThread)
 		{
 			if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL))
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"specialThreadSettings :: SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) failed 0x%X", GetLastError());
 #endif
 			}
 
 			if (NativeWinApi::NtSetInformationThread)
 			{
 				if (NativeWinApi::NtSetInformationThread(hThread, ThreadHideFromDebugger, 0, 0) != STATUS_SUCCESS)
 				{
 #ifdef DEBUG_COMMENTS
 					Scylla::debugLog.log(L"specialThreadSettings :: NtSetInformationThread ThreadHideFromDebugger failed");
 #endif
 				}
 			}
 		}
 	}
 
 	HANDLE DllInjection::startRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
 	{
 		HANDLE hThread = 0;
 
 		hThread = customCreateRemoteThread(hProcess, lpStartAddress, lpParameter);
 
 		if (hThread)
 		{
 			specialThreadSettings(hThread);
 			ResumeThread(hThread);
 		}
 
 		return hThread;
 	}
 
 	HANDLE DllInjection::customCreateRemoteThread(HANDLE hProcess, LPVOID lpStartAddress, LPVOID lpParameter)
 	{
 		DWORD lpThreadId = 0;
 		HANDLE hThread = 0;
 		NTSTATUS ntStatus = 0;
 
 		if (NativeWinApi::NtCreateThreadEx)
 		{
 			#define THREAD_ALL_ACCESS_VISTA_7 (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
 
 			//for windows vista/7
 			ntStatus = NativeWinApi::NtCreateThreadEx(&hThread, THREAD_ALL_ACCESS_VISTA_7, 0, hProcess, (LPTHREAD_START_ROUTINE)lpStartAddress, (LPVOID)lpParameter, TRUE, 0, 0, 0, 0);
 			if (NT_SUCCESS(ntStatus))
 			{
 				return hThread;
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"customCreateRemoteThread :: NtCreateThreadEx failed 0x%X", NativeWinApi::RtlNtStatusToDosError(ntStatus));
 #endif
 				return 0;
 			}
 		}
 		else
 		{
 			return CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)lpStartAddress,lpParameter,CREATE_SUSPENDED,&lpThreadId);
 		}
 	}
diff --git a/Scylla/DumpMemoryGui.cpp b/Scylla/DumpMemoryGui.cpp
index 39c8647..a05893b 100644
--- a/Scylla/DumpMemoryGui.cpp
+++ b/Scylla/DumpMemoryGui.cpp
@@ -1,573 +1,548 @@
 #include "DumpMemoryGui.h"
 
 #include "Architecture.h"
 #include "ProcessAccessHelp.h"
 #include <Psapi.h>
 #include "PeParser.h"
 
 WCHAR DumpMemoryGui::protectionString[100];
 const WCHAR DumpMemoryGui::MemoryUndefined[] = L"UNDEF";
 const WCHAR DumpMemoryGui::MemoryUnknown[] = L"UNKNOWN";
 const WCHAR * DumpMemoryGui::MemoryStateValues[] = {L"COMMIT",L"FREE",L"RESERVE"};
 const WCHAR * DumpMemoryGui::MemoryTypeValues[] = {L"IMAGE",L"MAPPED",L"PRIVATE"};
 const WCHAR * DumpMemoryGui::MemoryProtectionValues[] = {L"EXECUTE",L"EXECUTE_READ",L"EXECUTE_READWRITE",L"EXECUTE_WRITECOPY",L"NOACCESS",L"READONLY",L"READWRITE",L"WRITECOPY",L"GUARD",L"NOCACHE",L"WRITECOMBINE"};
 
 
 DumpMemoryGui::DumpMemoryGui()
 {
 	dumpedMemory = 0;
 	dumpedMemorySize = 0;
 	deviceNameResolver = new DeviceNameResolver();
 }
 DumpMemoryGui::~DumpMemoryGui()
 {
 	if (dumpedMemory)
 	{
 		delete [] dumpedMemory;
 	}
 
 	if (deviceNameResolver)
 	{
 		delete deviceNameResolver;
 	}
 
 	memoryList.clear();
 }
 BOOL DumpMemoryGui::OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
 {
 	DoDataExchange(); // attach controls
 	DlgResize_Init(true, true);
 
 	addColumnsToMemoryList(ListMemorySelect);
 	displayMemoryList(ListMemorySelect);
 
 	forceDump = false;
 	DoDataExchange(DDX_LOAD);
 
 	EditMemoryAddress.SetValue(ProcessAccessHelp::targetImageBase);
 	EditMemorySize.SetValue((DWORD)ProcessAccessHelp::targetSizeOfImage);
 
 	CenterWindow();
 	return TRUE;
 }
 
 void DumpMemoryGui::addColumnsToMemoryList(CListViewCtrl& list)
 {
 	list.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
 
 	list.InsertColumn(COL_ADDRESS, L"Address", LVCFMT_CENTER);
 	list.InsertColumn(COL_SIZE, L"Size", LVCFMT_CENTER);
 	list.InsertColumn(COL_FILENAME, L"File", LVCFMT_LEFT);
 	list.InsertColumn(COL_PESECTION, L"PE Section", LVCFMT_LEFT);
 
 	list.InsertColumn(COL_TYPE, L"Type", LVCFMT_CENTER);
 	list.InsertColumn(COL_PROTECTION, L"Protection", LVCFMT_CENTER);
 	list.InsertColumn(COL_STATE, L"State", LVCFMT_CENTER);
 
 	list.InsertColumn(COL_MAPPED_FILE, L"Mapped File", LVCFMT_LEFT);
 }
 
 void DumpMemoryGui::displayMemoryList(CListViewCtrl& list)
 {
 	int count = 0;
 	WCHAR temp[20];
 	list.DeleteAllItems();
 
 
 	getMemoryList();
 
 	std::vector<Memory>::const_iterator iter;
 
 	for( iter = memoryList.begin(); iter != memoryList.end(); iter++ , count++)
 	{
 		swprintf_s(temp, PRINTF_DWORD_PTR_FULL, iter->address);
 		list.InsertItem(count,temp);
 
 		swprintf_s(temp, L"%08X", iter->size);
 		list.SetItemText(count, COL_SIZE, temp);
 
 		list.SetItemText(count, COL_FILENAME, iter->filename);
 		list.SetItemText(count, COL_PESECTION, iter->peSection);
 
 		if (iter->state == MEM_FREE)
 		{
 			list.SetItemText(count, COL_TYPE, MemoryUndefined);
 		}
 		else
 		{
 			list.SetItemText(count, COL_TYPE, getMemoryTypeString(iter->type));
 		}
 
 		if ( (iter->state == MEM_RESERVE) || (iter->state == MEM_FREE) )
 		{
 			list.SetItemText(count, COL_PROTECTION, MemoryUndefined);
 		}
 		else
 		{
 			list.SetItemText(count, COL_PROTECTION, getMemoryProtectionString(iter->protect));
 		}
 		
 		list.SetItemText(count, COL_STATE, getMemoryStateString(iter->state));
 
 		list.SetItemText(count, COL_MAPPED_FILE, iter->mappedFilename);
 
 		list.SetItemData(count, (DWORD_PTR)&(*iter));
 	}
 
 	list.SetColumnWidth(COL_ADDRESS, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_SIZE, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_FILENAME, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_PESECTION, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_TYPE, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_PROTECTION, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_STATE, LVSCW_AUTOSIZE_USEHEADER);
 	list.SetColumnWidth(COL_MAPPED_FILE, LVSCW_AUTOSIZE_USEHEADER);
 }
 
 const WCHAR * DumpMemoryGui::getMemoryTypeString(DWORD value)
 {
 	switch(value)
 	{
 	case MEM_IMAGE:
 		return MemoryTypeValues[TYPE_IMAGE];
 	case MEM_MAPPED:
 		return MemoryTypeValues[TYPE_MAPPED];
 	case MEM_PRIVATE:
 		return MemoryTypeValues[TYPE_PRIVATE];
 	default:
 		return MemoryUnknown;
 	}
 }
 const WCHAR * DumpMemoryGui::getMemoryStateString(DWORD value)
 {
 	switch(value)
 	{
 	case MEM_COMMIT:
 		return MemoryStateValues[STATE_COMMIT];
 	case MEM_FREE:
 		return MemoryStateValues[STATE_FREE];
 	case MEM_RESERVE:
 		return MemoryStateValues[STATE_RESERVE];
 	default:
 		return MemoryUnknown;
 	}
 }
 
 WCHAR * DumpMemoryGui::getMemoryProtectionString(DWORD value)
 {
 	protectionString[0] = 0;
 
 	if (value & PAGE_GUARD)
 	{
 		wcscpy_s(protectionString, MemoryProtectionValues[PROT_GUARD]);
 		wcscat_s(protectionString, L" | ");
 		value ^= PAGE_GUARD;
 	}
 	if (value & PAGE_NOCACHE)
 	{
 		wcscpy_s(protectionString, MemoryProtectionValues[PROT_NOCACHE]);
 		wcscat_s(protectionString, L" | ");
 		value ^= PAGE_NOCACHE;
 	}
 	if (value & PAGE_WRITECOMBINE)
 	{
 		wcscpy_s(protectionString, MemoryProtectionValues[PROT_WRITECOMBINE]);
 		wcscat_s(protectionString, L" | ");
 		value ^= PAGE_WRITECOMBINE;
 	}
 
 	switch(value)
 	{
 	case PAGE_EXECUTE:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE]);
 			break;
 		}
 	case PAGE_EXECUTE_READ:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READ]);
 			break;
 		}
 	case PAGE_EXECUTE_READWRITE:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_READWRITE]);
 			break;
 		}
 	case PAGE_EXECUTE_WRITECOPY:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_EXECUTE_WRITECOPY]);
 			break;
 		}
 	case PAGE_NOACCESS:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_NOACCESS]);
 			break;
 		}
 	case PAGE_READONLY:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_READONLY]);
 			break;
 		}
 	case PAGE_READWRITE:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_READWRITE]);
 			break;
 		}
 	case PAGE_WRITECOPY:
 		{
 			wcscat_s(protectionString, MemoryProtectionValues[PROT_WRITECOPY]);
 			break;
 		}
 	default:
 		{
 			wcscat_s(protectionString, MemoryUnknown);
 		}
 	}
 
 	return protectionString;
 }
 
 
 LRESULT DumpMemoryGui::OnListMemoryColumnClicked(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
 	ListMemorySelect.SortItems(&listviewCompareFunc, MAKEWORD(column, ascending));
 
 	return 0;
 }
 LRESULT DumpMemoryGui::OnListMemoryClick(NMHDR* pnmh)
 {
 	int index = ListMemorySelect.GetSelectionMark();
 	if (index != -1)
 	{
 		selectedMemory = (Memory *)ListMemorySelect.GetItemData(index);
 		if (selectedMemory)
 		{
 			updateAddressAndSize(selectedMemory);
 		}
 		
 	}
 	return 0;
 }
 void DumpMemoryGui::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	DoDataExchange(DDX_SAVE);
 
 	if (EditMemoryAddress.GetValue() == 0 || EditMemorySize.GetValue() == 0)
 	{
 		wndCtl.MessageBoxW(L"Textbox is empty!",L"Error",MB_ICONERROR);
 	}
 	else
 	{
 		if (dumpMemory())
 		{
 			EndDialog(1);
 		}
 		else
 		{
 			wndCtl.MessageBoxW(L"Reading memory from process failed",L"Error",MB_ICONERROR);
 		}		
 	}	
 }
 void DumpMemoryGui::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	EndDialog(0);
 }
 
 void DumpMemoryGui::updateAddressAndSize( Memory * selectedMemory )
 {
 	EditMemoryAddress.SetValue(selectedMemory->address);
 	EditMemorySize.SetValue(selectedMemory->size);
 }
 
 int DumpMemoryGui::listviewCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
 {
 	const Memory * module1 = (Memory *)lParam1;
 	const Memory * module2 = (Memory *)lParam2;
 
 	int column = LOBYTE(lParamSort);
 	bool ascending = (HIBYTE(lParamSort) == TRUE);
 
 	int diff = 0;
 
 	switch(column)
 	{
 	case COL_ADDRESS:
 		diff = module1->address < module2->address ? -1 : 1;
 		break;
 	case COL_SIZE:
 		diff = module1->size < module2->size ? -1 : 1;
 		break;
 	case COL_FILENAME:
 		diff = _wcsicmp(module1->filename, module2->filename);
 		break;
 	case COL_PESECTION:
 		diff = _wcsicmp(module1->peSection, module2->peSection);
 		break;
 	case COL_TYPE:
 		diff = module1->type < module2->type ? -1 : 1;
 		break;
 	case COL_PROTECTION:
 		diff = module1->protect < module2->protect ? -1 : 1;
 		break;
 	case COL_STATE:
 		diff = _wcsicmp(getMemoryStateString(module1->state), getMemoryStateString(module2->state));
 		//diff = module1->state < module2->state ? -1 : 1;
 		break;
 	case COL_MAPPED_FILE:
 		diff = _wcsicmp(module1->mappedFilename, module2->mappedFilename);
 		break;
 	}
 
 	return ascending ? diff : -diff;
 }
 
 void DumpMemoryGui::getMemoryList()
 {
-	DWORD count = 0;
 	DWORD_PTR address = 0;
 	MEMORY_BASIC_INFORMATION memBasic = {0};
 	Memory memory;
 	HMODULE * hMods = 0;
-	DWORD cbNeeded = 0;
-	bool notEnough = true;
 	WCHAR target[MAX_PATH];
 
-	count = 100;
-	hMods = new HMODULE[count];
-
 	if (memoryList.empty())
 	{
 		memoryList.reserve(20);
 	}
 	else
 	{
 		memoryList.clear();
 	}
 
 	memory.filename[0] = 0;
 	memory.peSection[0] = 0;
 	memory.mappedFilename[0] = 0;
 
 	while(VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)address,&memBasic,sizeof(memBasic)))
 	{
 		memory.address = (DWORD_PTR)memBasic.BaseAddress;
 		memory.type = memBasic.Type;
 		memory.state = memBasic.State;
 		memory.size = (DWORD)memBasic.RegionSize;
 		memory.protect = memBasic.Protect;
 		
 
 		if (memory.type == MEM_MAPPED)
 		{
 			if (!getMappedFilename(&memory))
 			{
 				memory.mappedFilename[0] = 0;
 			}
 		}
 
 		memoryList.push_back(memory);
 
 		memory.mappedFilename[0] = 0;
 
 		address += memBasic.RegionSize;
 	}
 
-	do 
+	DWORD numHandles = ProcessAccessHelp::getModuleHandlesFromProcess(ProcessAccessHelp::hProcess, &hMods);
+	if (numHandles == 0)
 	{
-		if (!EnumProcessModules(ProcessAccessHelp::hProcess, hMods, count * sizeof(HMODULE), &cbNeeded))
-		{
-#ifdef DEBUG_COMMENTS
-			Scylla::debugLog.log(L"getMemoryList :: EnumProcessModules failed count %d", count);
-#endif
-			delete [] hMods;
-			return;
-		}
-
-		if ( (count * sizeof(HMODULE)) < cbNeeded )
-		{
-			delete [] hMods;
-			count += 100;
-			hMods = new HMODULE[count];
-		}
-		else
-		{
-			notEnough = false;
-		}
-	} while (notEnough);
+		return;
+	}
 
-	for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
+	for (DWORD i = 0; i < numHandles; i++)
 	{
 		if (GetModuleFileNameExW(ProcessAccessHelp::hProcess, hMods[i], target, _countof(target)))
 		{
 			setModuleName((DWORD_PTR)hMods[i],target);
 			setAllSectionNames((DWORD_PTR)hMods[i],target);
 		}
 		else
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"getMemoryList :: GetModuleFileNameExW failed 0x%X", GetLastError());
 #endif
 		}
 	}
 
 	delete [] hMods;
-
-
 }
 
 void DumpMemoryGui::setSectionName(DWORD_PTR sectionAddress, DWORD sectionSize, const WCHAR * sectionName)
 {
 	bool found = false;
 	std::vector<Memory>::const_iterator iter;
 
 
 	for( iter = memoryList.begin(); iter != memoryList.end(); iter++)
 	{
 		if (!found)
 		{
 			if ( (iter->address <= sectionAddress) && (sectionAddress < (iter->address + iter->size)) )
 			{
 				if (wcslen(iter->peSection) == 0)
 				{
 					wcscpy_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName);
 				}
 				else
 				{
 					wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), L"|");
 					wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName);
 				}
 				
 				found = true;
 			}
 		}
 		else
 		{
 			if ((sectionSize+sectionAddress) < iter->address)
 			{
 				break;
 			}
 			if (wcslen(iter->peSection) == 0)
 			{
 				wcscpy_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName);
 			}
 			else
 			{
 				wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), L"|");
 				wcscat_s((WCHAR *)iter->peSection, _countof(iter->peSection), sectionName);
 			}
 		}
 
 	}
 }
 
 void DumpMemoryGui::setModuleName(DWORD_PTR moduleBase, const WCHAR * moduleName)
 {
 	bool found = false;
 	std::vector<Memory>::const_iterator iter;
 
 	//get filename
 	const WCHAR* slash = wcsrchr(moduleName, L'\\');
 	if(slash)
 	{
 		moduleName = slash+1;
 	}
 
 
 	for( iter = memoryList.begin(); iter != memoryList.end(); iter++)
 	{
 		if (iter->address == moduleBase)
 		{
 			found = true;
 		}
 
 		if (found)
 		{
 			if (iter->type == MEM_IMAGE)
 			{
 				wcscpy_s((WCHAR *)iter->filename, MAX_PATH, moduleName);
 			}
 			else
 			{
 				break;
 			}
 		}
 	}
 }
 
 void DumpMemoryGui::setAllSectionNames( DWORD_PTR moduleBase, WCHAR * moduleName )
 {
 	WCHAR sectionNameW[IMAGE_SIZEOF_SHORT_NAME + 1] = {0};
 
 	PeParser peFile(moduleName);
 
 	if (peFile.isValidPeFile())
 	{
 		std::vector<PeFileSection> & listSectionHeader = peFile.getSectionHeaderList();
 
 		for (WORD i = 0; i < peFile.getNumberOfSections(); i++)
 		{
 			peFile.getSectionNameUnicode(i, sectionNameW, _countof(sectionNameW));
 
 			setSectionName(moduleBase + listSectionHeader[i].sectionHeader.VirtualAddress, listSectionHeader[i].sectionHeader.Misc.VirtualSize, sectionNameW);
 		}
 	}
 	else
 	{
 		MessageBox(moduleName,L"Not a valid PE -> This should never happen",MB_ICONERROR);
 	}
 
 }
 
 bool DumpMemoryGui::dumpMemory()
 {
 	DWORD_PTR address = EditMemoryAddress.GetValue();
 	dumpedMemorySize = EditMemorySize.GetValue();
 
 	swprintf_s(dumpFilename,TEXT("MEM_")TEXT(PRINTF_DWORD_PTR_FULL_S)TEXT("_")TEXT("%08X"),address,dumpedMemorySize);
 
 	dumpedMemory = new BYTE[dumpedMemorySize];
 
 	if (dumpedMemory)
 	{
 		if (forceDump)
 		{
 			return ProcessAccessHelp::readMemoryPartlyFromProcess(address,dumpedMemorySize,dumpedMemory);
 		}
 		else
 		{
 			return ProcessAccessHelp::readMemoryFromProcess(address,dumpedMemorySize,dumpedMemory);
 		}
 		
 	}
 	else
 	{
 		return false;
 	}
 }
 
 bool DumpMemoryGui::getMappedFilename( Memory* memory )
 {
 	WCHAR filename[MAX_PATH] = {0};
 
 	//TODO replace with Nt direct syscall
 	if (GetMappedFileNameW(ProcessAccessHelp::hProcess, (LPVOID)memory->address, filename, _countof(filename)) > 0)
 	{
 		return deviceNameResolver->resolveDeviceLongNameToShort(filename, memory->mappedFilename);
 	}
 
 	return false;
 }
diff --git a/Scylla/MainGui.cpp b/Scylla/MainGui.cpp
index 0c00987..6011d8e 100644
--- a/Scylla/MainGui.cpp
+++ b/Scylla/MainGui.cpp
@@ -1,1395 +1,1395 @@
 #include "MainGui.h"
 
 #include "Architecture.h"
 //#include "PluginLoader.h"
 //#include "ConfigurationHolder.h"
 #include "PeParser.h"
 #include "DllInjectionPlugin.h"
 #include "DisassemblerGui.h"
 #include "PickApiGui.h"
 //#include "NativeWinApi.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::OnDisassembler(UINT uNotifyCode, int nID, CWindow wndCtl)
 {
 	disassemblerActionHandler();
 }
 
 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);
+			DisassemblerGui dlgDisassembler(address, &apiReader);
 			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);
 		}
 
 		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.EnableMenuItem(ID_MISC_DISASSEMBLER, 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::disassemblerActionHandler()
 {
 	DWORD_PTR oep = EditOEPAddress.GetValue();
-	DisassemblerGui disGuiDlg(oep);
+	DisassemblerGui disGuiDlg(oep, &apiReader);
 	disGuiDlg.DoModal();
 }
 
 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/PeParser.cpp b/Scylla/PeParser.cpp
index 39d57f7..b361022 100644
--- a/Scylla/PeParser.cpp
+++ b/Scylla/PeParser.cpp
@@ -1,1233 +1,1210 @@
 
 #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)
+bool PeParser::readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection)
+{
+	return readSectionFrom(readOffset, peFileSection, true); //process
+}
+
+bool PeParser::readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection)
+{
+	return readSectionFrom(readOffset, peFileSection, false); //file
+}
+
+bool PeParser::readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess)
 {
 	const DWORD maxReadSize = 100;
+	DWORD currentReadSize;
 	BYTE data[maxReadSize];
-	DWORD bytesRead = 0;
 	bool retValue = true;
 	DWORD valuesFound = 0;
-	DWORD currentOffset = 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 readPeSectionFromFile(readOffset, peFileSection);
+		if (isProcess)
+		{
+			return readPeSectionFromProcess(readOffset, peFileSection);
+		}
+		else
+		{
+			return readPeSectionFromFile((DWORD)readOffset, peFileSection);
+		}
+	}
+
+	currentReadSize = readSize % maxReadSize; //alignment %
+
+	if (!currentReadSize)
+	{
+		currentReadSize = maxReadSize;
 	}
+	currentOffset = readOffset + readSize - currentReadSize;
 
-	currentOffset = readOffset + readSize - maxReadSize;
 
 	while(currentOffset >= readOffset) //start from the end
 	{
-		SetFilePointer(hFile, currentOffset, 0, FILE_BEGIN);
+		ZeroMemory(data, currentReadSize);
 
-		ZeroMemory(data, sizeof(data));
-		if (!ReadFile(hFile, data, sizeof(data), &bytesRead, 0))
+		if (isProcess)
+		{
+			retValue = ProcessAccessHelp::readMemoryPartlyFromProcess(currentOffset, currentReadSize, data);
+		}
+		else
+		{
+			retValue = ProcessAccessHelp::readMemoryFromFile(hFile, (LONG)currentOffset, currentReadSize, data);
+		}
+
+		if (!retValue)
 		{
-			retValue = false;
 			break;
 		}
 
-		valuesFound = isMemoryNotNull(data, sizeof(data));
+		valuesFound = isMemoryNotNull(data, currentReadSize);
 		if (valuesFound)
 		{
 			//found some real code
 
 			currentOffset += valuesFound;
 
 			if (readOffset < currentOffset)
 			{
 				//real size
-				peFileSection.dataSize = currentOffset - readOffset;
+				peFileSection.dataSize = (DWORD)(currentOffset - readOffset);
 			}
 
 			break;
 		}
 
-		currentOffset -= maxReadSize;
+		currentReadSize = maxReadSize;
+		currentOffset -= currentReadSize;
 	}
 
 	if (peFileSection.dataSize)
 	{
-		retValue = readPeSectionFromFile(readOffset, peFileSection);
+		if (isProcess)
+		{
+			retValue = readPeSectionFromProcess(readOffset, peFileSection);
+		}
+		else
+		{
+			retValue = readPeSectionFromFile((DWORD)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;
 }
 
 int PeParser::convertRVAToOffsetVectorIndex(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 i;
 		}
 	}
 
 	return -1;
 }
 
 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 = entryPoint;
 	}
 	else if (isPE64())
 	{
 		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 329354b..b3dc055 100644
--- a/Scylla/PeParser.h
+++ b/Scylla/PeParser.h
@@ -1,132 +1,136 @@
 #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(&sectionHeader, 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 readSectionFromProcess(const DWORD_PTR readOffset, PeFileSection & peFileSection );
+	bool readSectionFromFile(const DWORD readOffset, PeFileSection & peFileSection );
+	bool readSectionFrom(const DWORD_PTR readOffset, PeFileSection & peFileSection, const bool isProcess);
+
+	
+	
 
 	bool addNewLastSection(const CHAR * sectionName, DWORD sectionSize, BYTE * sectionData);
 	DWORD alignValue(DWORD badValue, DWORD alignTo);
 	int convertRVAToOffsetVectorIndex(DWORD_PTR dwRVA);
 	DWORD_PTR convertOffsetToRVAVector(DWORD_PTR dwOffset);
 	DWORD_PTR convertRVAToOffsetVector(DWORD_PTR dwRVA);
 	void setNumberOfSections(WORD numberOfSections);
 	
 	void removeIatDirectory();
 	bool getFileOverlay();
 };
 
diff --git a/Scylla/ProcessAccessHelp.cpp b/Scylla/ProcessAccessHelp.cpp
index 91aee0d..0cc8123 100644
--- a/Scylla/ProcessAccessHelp.cpp
+++ b/Scylla/ProcessAccessHelp.cpp
@@ -1,785 +1,819 @@
 
 #include "ProcessAccessHelp.h"
 
 #include "Scylla.h"
 #include "NativeWinApi.h"
 #include "PeParser.h"
 
 HANDLE ProcessAccessHelp::hProcess = 0;
 
 ModuleInfo * ProcessAccessHelp::selectedModule;
 DWORD_PTR ProcessAccessHelp::targetImageBase = 0;
 DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0;
 DWORD_PTR ProcessAccessHelp::maxValidAddress = 0;
 
 std::vector<ModuleInfo> ProcessAccessHelp::moduleList; //target process module list
 std::vector<ModuleInfo> ProcessAccessHelp::ownModuleList; //own module list
 
 
 _DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS];
 unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0;
 _CodeInfo ProcessAccessHelp::decomposerCi = {0};
 
 _DecodedInst  ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS];
 unsigned int  ProcessAccessHelp::decodedInstructionsCount = 0;
 
 BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
 
 //#define DEBUG_COMMENTS
 
 bool ProcessAccessHelp::openProcessHandle(DWORD dwPID)
 {
 	if (dwPID > 0)
 	{
 		if (hProcess)
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess);
 #endif
 			return false;
 		}
 		else
 		{
 			//hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID);
 			//if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid)))
 
 			hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, dwPID);
 
 			if (hProcess)
 			{
 				return true;
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID);
 #endif
 				return false;
 			}
 		}
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID);
 #endif
 		return false;
 	}
 	
 }
 
 HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId)
 {
 	HANDLE hProcess = 0;
 	CLIENT_ID cid = {0};
 	OBJECT_ATTRIBUTES ObjectAttributes;
 	NTSTATUS ntStatus = 0;
 
 	InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0);
 	cid.UniqueProcess = (HANDLE)dwProcessId;
 
 	ntStatus = NativeWinApi::NtOpenProcess(&hProcess,dwDesiredAccess,&ObjectAttributes, &cid);
 
 	if (NT_SUCCESS(ntStatus))
 	{
 		return hProcess;
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus));
 #endif
 		return 0;
 	}
 }
 
 void ProcessAccessHelp::closeProcessHandle()
 {
 	CloseHandle(hProcess);
 	hProcess = 0;
 	moduleList.clear();
 	targetImageBase = 0;
 	selectedModule = 0;
 }
 
 bool ProcessAccessHelp::readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
 {
 	DWORD_PTR addressPart = 0;
 	DWORD_PTR readBytes = 0;
 	DWORD_PTR bytesToRead = 0;
 	MEMORY_BASIC_INFORMATION memBasic = {0};
 	bool returnValue = false;
 
 	if (!hProcess)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: hProcess == NULL");
 #endif
 		return returnValue;
 	}
 
 	if (!readMemoryFromProcess(address, size, dataBuffer))
 	{
 		addressPart = address;
 
 		do 
 		{
 			if (!VirtualQueryEx(ProcessAccessHelp::hProcess,(LPCVOID)addressPart,&memBasic,sizeof(memBasic)))
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: Error VirtualQueryEx %X %X err: %u", addressPart,size, GetLastError());
 #endif
 				break;
 			}
 
 			bytesToRead = memBasic.RegionSize;
 
 			if ( (readBytes+bytesToRead) > size)
 			{
 				bytesToRead = size - readBytes;
 			}
 
 			if (memBasic.State == MEM_COMMIT)
 			{
 				if (!readMemoryFromProcess(addressPart, bytesToRead, (LPVOID)((DWORD_PTR)dataBuffer + readBytes)))
 				{
 					break;
 				}
 			}
 			else
 			{
 				ZeroMemory((LPVOID)((DWORD_PTR)dataBuffer + readBytes),bytesToRead);
 			}
 
 
 			readBytes += bytesToRead;
 
 			addressPart += memBasic.RegionSize;
 
 		} while (readBytes < size);
 
 		if (readBytes == size)
 		{
 			returnValue = true;
 		}
 		
 	}
 	else
 	{
 		returnValue = true;
 	}
 
 	return returnValue;
 }
 
 bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
 {
 	SIZE_T lpNumberOfBytesRead = 0;
 	DWORD dwProtect = 0;
 	bool returnValue = false;
 
 	if (!hProcess)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL");
 #endif
 		return returnValue;
 	}
 
 	if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
 #endif
 		if (!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect))
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address,size, GetLastError());
 #endif
 			returnValue = false;
 		}
 		else
 		{
 			if (!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
 #endif
 				returnValue = false;
 			}
 			else
 			{
 				returnValue = true;
 			}
 			VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect);
 		}
 	}
 	else
 	{
 		returnValue = true;
 	}
 
 	if (returnValue)
 	{
 		if (size != lpNumberOfBytesRead)
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size);
 #endif
 			returnValue = false;
 		}
 		else
 		{
 			returnValue = true;
 		}
 	}
 	
 	return returnValue;
 }
 
 bool ProcessAccessHelp::decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress)
 {
 
 	ZeroMemory(&decomposerCi, sizeof(_CodeInfo));
 	decomposerCi.code = dataBuffer;
 	decomposerCi.codeLen = (int)bufferSize;
 	decomposerCi.dt = dt;
 	decomposerCi.codeOffset = startAddress;
 
 	decomposerInstructionsCount = 0;
 
 	if (distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult)/sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR");
 #endif
 		return false;
 	}
 	else
 	{
 		return true;
 	}
 }
 
 bool ProcessAccessHelp::disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset)
 {
 	// Holds the result of the decoding.
 	_DecodeResult res;
 
 	// next is used for instruction's offset synchronization.
 	// decodedInstructionsCount holds the count of filled instructions' array by the decoder.
 
 	decodedInstructionsCount = 0;
 
 	_OffsetType offset = startOffset;
 
 	res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount);
 
 /*	for (unsigned int i = 0; i < decodedInstructionsCount; i++) {
 #ifdef SUPPORT_64BIT_OFFSET
 		printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
 #else
 		printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
 #endif
 
 	}*/
 
 	if (res == DECRES_INPUTERR)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR");
 #endif
 		return false;
 	}
 	else if (res == DECRES_SUCCESS)
 	{
 		//printf("disassembleMemory :: res == DECRES_SUCCESS\n");
 		return true;
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"disassembleMemory :: res == %d", res);
 #endif
 		return false;
 	}
 }
 
 DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask)
 {
 	DWORD pos = 0;
 	size_t searchLen = strlen(mask) - 1;
 
 	for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++)
 	{
 		if( *(BYTE*)retAddress == pattern[pos] || mask[pos] == '?' )
 		{
 			if(mask[pos+1] == 0x00)
 			{
 				return (retAddress - searchLen);
 			}
 			pos++;
 		} else {
 			pos = 0;
 		}
 	}
 	return 0;
 }
 
 bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR * filePath)
 {
 	return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath);
 }
 
 LONGLONG ProcessAccessHelp::getFileSize(const WCHAR * filePath)
 {
 	LONGLONG fileSize = 0;
 
 	HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
 
 	if (hFile != INVALID_HANDLE_VALUE)
 	{
 		fileSize = getFileSize(hFile);
 		CloseHandle(hFile);
 	}
 	
 	return fileSize;
 }
 
 LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile)
 {
 	LARGE_INTEGER lpFileSize = {0};
 
 	if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
 	{
 		if (!GetFileSizeEx(hFile, &lpFileSize))
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError());
 #endif
 			return 0;
 		}
 		else
 		{
 			return lpFileSize.QuadPart;
 		}
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid");
 #endif
 		return 0;
 	}
 }
 
 
 bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer)
 {
 	DWORD lpNumberOfBytesRead = 0;
 	DWORD retValue = 0;
 	DWORD dwError = 0;
 
-	if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
+	if (hFile != INVALID_HANDLE_VALUE)
 	{
 		retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
 		dwError = GetLastError();
 
 		if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError);
 #endif
 			return false;
 		}
 		else
 		{
 			if (ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0))
 			{
 				return true;
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError());
 #endif
 				return false;
 			}
 		}
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid");
 #endif
 		return false;
 	}
 }
 
 bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer)
 {
 	HANDLE hFile = CreateFile(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
 
 	if (hFile != INVALID_HANDLE_VALUE)
 	{
 		return writeMemoryToFile(hFile,0,size,dataBuffer);
 	}
 	else
 	{
 		return false;
 	}
 }
 
 bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer)
 {
 	DWORD lpNumberOfBytesWritten = 0;
 	DWORD retValue = 0;
 	DWORD dwError = 0;
 
-	if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
+	if ((hFile != INVALID_HANDLE_VALUE) && dataBuffer)
 	{
 		retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
 		dwError = GetLastError();
 
 		if ((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError);
 #endif
 			return false;
 		}
 		else
 		{
 			if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
 			{
 				return true;
 			}
 			else
 			{
 #ifdef DEBUG_COMMENTS
 				Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError());
 #endif
 				return false;
 			}
 		}
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid");
 #endif
 		return false;
 	}
 }
 
 bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer)
 {
 	DWORD lpNumberOfBytesWritten = 0;
 	DWORD retValue = 0;
 
 	if ((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
 	{
 		SetFilePointer(hFile, 0, 0, FILE_END);
 
 		if (WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
 		{
 			return true;
 		}
 		else
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError());
 #endif
 			return false;
 		}
 	}
 	else
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid");
 #endif
 		return false;
 	}
 }
 
 bool ProcessAccessHelp::readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath)
 {
 	DWORD lpNumberOfBytesRead = 0;
 	LONGLONG fileSize = 0;
 	DWORD dwSize = 0;
 	bool returnValue = 0;
 
 	HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
 
 	if( hFile == INVALID_HANDLE_VALUE )
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError());
 #endif
 		returnValue = false;
 	}
 	else
 	{
 		fileSize = getFileSize(hFile);
 
 		if (fileSize > 0)
 		{
 			if (fileSize > bufferSize)
 			{
 				dwSize = bufferSize;
 			}
 			else
 			{
 				dwSize = (DWORD)(fileSize - 1);
 			}
 
 			returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer);
 		}
 
 		CloseHandle(hFile);
 	}
 
 	return returnValue;
 }
 
 LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR * filePath)
 {
 	return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ);
 }
 
 LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR * filePath)
 {
 	return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS);
 }
 
 LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap)
 {
 	HANDLE hFile = CreateFile(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
 
 	if( hFile == INVALID_HANDLE_VALUE )
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
 #endif
 		return NULL;
 	}
 
 	HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL);
 	CloseHandle(hFile);
 
 	if( hMappedFile == NULL )
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL");
 #endif
 		return NULL;
 	}
 
 	if (GetLastError() == ERROR_ALREADY_EXISTS)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS");
 #endif
 		return NULL;
 	}
 
 	LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0);
 
 	if( addrMappedDll == NULL )
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
 #endif
 		CloseHandle(hMappedFile);
 		return NULL;
 	}
 
 	CloseHandle(hMappedFile);
 
 	return addrMappedDll;
 }
 
 DWORD ProcessAccessHelp::getProcessByName(const WCHAR * processName)
 {
 	DWORD dwPID = 0;
 	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 	PROCESSENTRY32W pe32;
 	pe32.dwSize = sizeof(PROCESSENTRY32W);
 
 	if( !Process32FirstW( hProcessSnap, &pe32 ) )
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"getProcessByName :: Error getting first Process");
 #endif
 		CloseHandle( hProcessSnap );
 		return 0;
 	}
 
 	do
 	{
 		if(!_wcsicmp(pe32.szExeFile, processName)) 
 		{
 			dwPID = pe32.th32ProcessID;
 			break;
 		}
 	} while(Process32NextW(hProcessSnap, &pe32));
 
 	CloseHandle(hProcessSnap);
 
 	return dwPID;
 }
 
 bool ProcessAccessHelp::getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList)
 {
 	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
 	MODULEENTRY32 me32;
 	ModuleInfo module;
 
 	// Take a snapshot of all modules in the specified process.
 	hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
 	if( hModuleSnap == INVALID_HANDLE_VALUE )
 	{
 		return false;
 	}
 
 	// Set the size of the structure before using it.
 	me32.dwSize = sizeof( MODULEENTRY32 );
 
 	// Retrieve information about the first module,
 	// and exit if unsuccessful
 	if( !Module32First( hModuleSnap, &me32 ) )
 	{
 		CloseHandle( hModuleSnap );
 		return false;
 	}
 
 	// Now walk the module list of the process,
 	// and display information about each module
 
 	//the first is always the .exe
 	if (!Module32Next(hModuleSnap, &me32))
 	{
 		CloseHandle( hModuleSnap );
 		return false;
 	}
 
 	moduleList.reserve(20);
 
 	do
 	{
 		//printf(L"\n     MODULE NAME:     %s",   me32.szModule);
 		module.modBaseAddr = (DWORD_PTR)me32.modBaseAddr;
 		module.modBaseSize = me32.modBaseSize;
 		module.isAlreadyParsed = false;
 		module.parsing = false;
 		wcscpy_s(module.fullPath, me32.szExePath);
 
 		moduleList.push_back(module);
 
 	} while(Module32Next(hModuleSnap, &me32));
 
 	CloseHandle( hModuleSnap );
 	return true;
 }
 
 bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize)
 {
 	MEMORY_BASIC_INFORMATION memBasic;
 
 	if (VirtualQueryEx(hProcess,(LPCVOID)address,&memBasic,sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError());
 #endif
 		return false;
 	}
 	else
 	{
 		*memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress;
 		*memoryRegionSize = memBasic.RegionSize;
 		return true;
 	}
 }
 
 bool ProcessAccessHelp::getSizeOfImageCurrentProcess()
 {
 	DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase);
 
 	if (newSizeOfImage != 0)
 	{
 		ProcessAccessHelp::targetSizeOfImage = newSizeOfImage;
 		return true;
 	}
 	else
 	{
 		return false;
 	}
 }
 
 SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase)
 {
 	SIZE_T sizeOfImage = 0;
 	MEMORY_BASIC_INFORMATION lpBuffer = {0};
 	SIZE_T dwLength = sizeof(MEMORY_BASIC_INFORMATION);
 
 	do
 	{
 		moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize);
 		sizeOfImage += lpBuffer.RegionSize;
 
 		//printf("Query 0x"PRINTF_DWORD_PTR_FULL" size 0x%08X\n",moduleBase,sizeOfImage);
 
 		if (!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, dwLength))
 		{
 #ifdef DEBUG_COMMENTS
 			Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError());
 #endif
 			lpBuffer.Type = 0;
 			sizeOfImage = 0;
 		}
 		/*else
 		{
 			printf("\nAllocationBase %X\n",lpBuffer.AllocationBase);
 			printf("AllocationProtect %X\n",lpBuffer.AllocationProtect);
 			printf("BaseAddress %X\n",lpBuffer.BaseAddress);
 			printf("Protect %X\n",lpBuffer.Protect);
 			printf("RegionSize %X\n",lpBuffer.RegionSize);
 			printf("State %X\n",lpBuffer.State);
 			printf("Type %X\n",lpBuffer.Type);
 		}*/
 	} while (lpBuffer.Type == MEM_IMAGE);
 
 	//printf("Real sizeOfImage %X\n",sizeOfImage);
 
 	return sizeOfImage;
 }
 
 DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR * filePath)
 {
 	PeParser peFile(filePath, false);
 
 	return peFile.getEntryPoint();
 }
 
 bool ProcessAccessHelp::createBackupFile(const WCHAR * filePath)
 {
 	size_t fileNameLength = wcslen(filePath) + 5; //.bak + null
 	BOOL retValue = 0;
 
 	WCHAR * backupFile = new WCHAR[fileNameLength];
 
 	wcscpy_s(backupFile, fileNameLength, filePath);
 	wcscat_s(backupFile, fileNameLength, L".bak");
 	retValue = CopyFile(filePath, backupFile, FALSE);
 
 	if (!retValue)
 	{
 #ifdef DEBUG_COMMENTS
 		Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError());
 #endif
 	}
 
 	delete [] backupFile;
 
 	return retValue != 0;
 }
+
+DWORD ProcessAccessHelp::getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods)
+{
+	DWORD count = 30;
+	DWORD cbNeeded = 0;
+	bool notEnough = true;
+
+	*hMods = new HMODULE[count];
+
+	do 
+	{
+		if (!EnumProcessModules(hProcess, *hMods, count * sizeof(HMODULE), &cbNeeded))
+		{
+#ifdef DEBUG_COMMENTS
+			Scylla::debugLog.log(L"getModuleHandlesFromProcess :: EnumProcessModules failed count %d", count);
+#endif
+			delete [] *hMods;
+			return 0;
+		}
+
+		if ((count * sizeof(HMODULE)) < cbNeeded)
+		{
+			delete [] *hMods;
+			count = cbNeeded / sizeof(HMODULE);
+			*hMods = new HMODULE[count];
+		}
+		else
+		{
+			notEnough = false;
+		}
+	} while (notEnough);
+
+	return cbNeeded / sizeof(HMODULE);
+}
\ No newline at end of file
diff --git a/Scylla/ProcessAccessHelp.h b/Scylla/ProcessAccessHelp.h
index c5fc3c0..a2087e2 100644
--- a/Scylla/ProcessAccessHelp.h
+++ b/Scylla/ProcessAccessHelp.h
@@ -1,217 +1,219 @@
 #pragma once
 
 #include <windows.h>
 #include <tlhelp32.h>
 #include <vector>
 
 /************************************************************************/
 /* distorm                                                              */
 /************************************************************************/
 #include <distorm.h>
 
 // The number of the array of instructions the decoder function will use to return the disassembled instructions.
 // Play with this value for performance...
 #define MAX_INSTRUCTIONS (200)
 
 /************************************************************************/
 
 class ApiInfo;
 
 class ModuleInfo
 {
 public:
 
 	WCHAR fullPath[MAX_PATH];
 	DWORD_PTR modBaseAddr;
 	DWORD modBaseSize;
 
 	bool isAlreadyParsed;
 	bool parsing;
 
 	/*
 	  for iat rebuilding with duplicate entries:
 
 	  ntdll = low priority
 	  kernelbase = low priority
 	  SHLWAPI = low priority
 
 	  kernel32 = high priority
 	  
 	  priority = 1 -> normal/high priority
 	  priority = 0 -> low priority
 	*/
 	int priority;
 
 	std::vector<ApiInfo *> apiList;
 
 	ModuleInfo()
 	{
 		modBaseAddr = 0;
 		modBaseSize = 0;
 		priority = 1;
 		isAlreadyParsed = false;
 		parsing = false;
 	}
 
 	const WCHAR * getFilename() const
 	{
 		const WCHAR* slash = wcsrchr(fullPath, L'\\');
 		if(slash)
 		{
 			return slash+1;
 		}
 		return fullPath;
 	}
 };
 
 class ApiInfo
 {
 public:
 
 	char name[MAX_PATH];
 	WORD hint;
 	DWORD_PTR va;
 	DWORD_PTR rva;
 	WORD ordinal;
 	bool isForwarded;
 	ModuleInfo * module;
 };
 
 class ProcessAccessHelp
 {
 public:
 
 	static HANDLE hProcess; //OpenProcess handle to target process
 
 	static DWORD_PTR targetImageBase;
 	static DWORD_PTR targetSizeOfImage;
 	static DWORD_PTR maxValidAddress;
 
 	static ModuleInfo * selectedModule;
 
 	static std::vector<ModuleInfo> moduleList; //target process module list
 	static std::vector<ModuleInfo> ownModuleList; //own module list
 
 	static const size_t PE_HEADER_BYTES_COUNT = 2000;
 
 	static BYTE fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
 
 
 	//for decomposer
 	static _DInst decomposerResult[MAX_INSTRUCTIONS];
 	static unsigned int decomposerInstructionsCount;
 	static _CodeInfo decomposerCi;
 
 	//distorm :: Decoded instruction information.
 	static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS];
 	static unsigned int decodedInstructionsCount;
 #ifdef _WIN64
 	static const _DecodeType dt = Decode64Bits;
 #else
 	static const _DecodeType dt = Decode32Bits;
 #endif
 
 	/*
 	 * Open a new process handle
 	 */
 	static bool openProcessHandle(DWORD dwPID);
 
 	static HANDLE NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId);
 
 	static void closeProcessHandle();
 
 	/*
 	 * Get all modules from a process
 	 */
 	static bool getProcessModules(DWORD dwPID, std::vector<ModuleInfo> &moduleList);
 
 
 	/*
 	 * file mapping view with different access level
 	 */
 	static LPVOID createFileMappingViewRead(const WCHAR * filePath);
 	static LPVOID createFileMappingViewFull(const WCHAR * filePath);
 
 	/*
 	 * Create a file mapping view of a file 
 	 */
 	static LPVOID createFileMappingView(const WCHAR * filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap);
 
 	/*
 	 * Read memory from target process
 	 */
 	static bool readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer);
 
 	/*
 	 * Read memory from target process and ignore no data pages
 	 */
 	static bool readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer);
 
 	/*
 	 * Read memory from file
 	 */
 	static bool readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer);
 
 	/*
 	 * Write memory to file
 	 */
 	static bool writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer);
 
 
 	/*
 	 * Write memory to new file
 	 */
 	static bool writeMemoryToNewFile(const WCHAR * file,DWORD size, LPCVOID dataBuffer);
 
 	/*
 	 * Write memory to file end
 	 */
 	static bool writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer);
 
 	/*
 	 * Disassemble Memory
 	 */
 	static bool disassembleMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset);
 
 	static bool decomposeMemory(BYTE * dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress);
 
 	/*
 	 * Search for pattern
 	 */
 	static DWORD_PTR findPattern(DWORD_PTR startOffset, DWORD size, BYTE * pattern, const char * mask);
 
 	/*
 	 * Get process ID by process name
 	 */
 	static DWORD getProcessByName(const WCHAR * processName);
 
 	/*
 	 * Get memory region from address
 	 */
 	static bool getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR * memoryRegionBase, SIZE_T * memoryRegionSize);
 
 
 	/*
 	 * Read PE Header from file
 	 */
 	static bool readHeaderFromFile(BYTE * buffer, DWORD bufferSize, const WCHAR * filePath);
 
 	static bool readHeaderFromCurrentFile(const WCHAR * filePath);
 
 	/*
 	 * Get real sizeOfImage value
 	 */
 	static SIZE_T getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase);
 
 	/*
 	 * Get real sizeOfImage value current process
 	 */
 	static bool getSizeOfImageCurrentProcess();
 
 	static LONGLONG getFileSize(HANDLE hFile);
 	static LONGLONG getFileSize(const WCHAR * filePath);
 
 	static DWORD getEntryPointFromFile(const WCHAR * filePath);
 
 	static bool createBackupFile(const WCHAR * filePath);
+
+	static DWORD getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE ** hMods );
 };
diff --git a/Scylla/Scylla.h b/Scylla/Scylla.h
index 2e6a862..98fea0d 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.7 Beta 2"
+#define APPVERSION_S "v0.7 Beta 4"
 
 #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[];
 };