⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shubloadercore.cpp

📁 此为破解装载器一书中的源代码,在看雪论坛下载的,
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// ShubLoaderCore.cpp : Defines the entry point for the console application.
//

#include "NTInternals.h"
#include "ShubLoaderCore.h"
#include <Winbase.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// The one and only application object

using namespace std;

//////////////////////////////////////////////////////////////////////////

//This data member is static because it's easiest to handle it from derived classes.
HWND ShubLoaderCore::m_ghMainWnd;
BOOL ShubLoaderCore::m_SilentMode;

ShubLoaderCore::ShubLoaderCore() 
{
	m_ghMainWnd=NULL;
	m_SilentMode=FALSE;
	memset(&pi, 0, sizeof(PROCESS_INFORMATION));
	m_bcheckCRC=FALSE;
	m_dwVictimCRCValue=0;
	m_dwCreationFlags=CREATE_SUSPENDED;
	
	//default message if not specified otherwise using SetStartingMsg()
	m_startingMsg="Shub-Nigurrath Loader is working...wait a little\n";
}

void ShubLoaderCore::SetMainWnd(HWND hWnd)
{
	m_ghMainWnd = hWnd;
}

void ShubLoaderCore::SetSilentMode(BOOL bVal)
{
	m_SilentMode= bVal;
}


int ShubLoaderCore::DoMyJob(int argc, TCHAR* argv[]) 
{
	growing_arraystack<TextString> stkErrors;
	growing_arraystack<Patch> stkPatches;
	
	//Victim's parameters. Set by the function SetVictimPathandCRC().
	TextString victimFileName;
	
	
	//The whole patcher code is into a Try block because I will trap the errors
	//into an unique place at the end of the function.
	try {
		
		//Must be properly defined in the LoaderActions.cpp file by the Loader creator
		if(!InitializePatchStack(stkPatches))
			throw BAD_INITIALIZEPATCHSTACK;

		//Must be properly called by the developers into LoaderActions.cpp.
		if(!SetVictimDetails(victimFileName))
			throw BAD_SETVICTIMPATHANDCRC;
		
		//////////////////////////////////////////////////////////////////////////
		//This gate variable is set by the Gate Procedure when the condition required to patch
		//the application is met.
		//The condition that can be used to patch the application can be of different types: 
		//presence of the main window; presence of a specific value in memory; 
		//presence of a specific file on the disk and so on..
		BOOL bCanPatchVictim=FALSE;

		BOOL bProcessOpened=FALSE;

		#ifdef _DEBUG
		TextString strFinalReport; //string used to write the final MessageBox
		#endif
		
		//Number of patches pushed into the patches stack. 
		//It's used when the program is compiled in debugmode to report how bytes will be written
		int NumberofPatches= stkPatches.size();

		//Create the process
		//PROCESS_INFORMATION have already been declared into the class's attributes.
		STARTUPINFO si;
		memset(&si, 0, sizeof(STARTUPINFO));
		si.cb=sizeof(si);

		if(!ActionsBeforeCreateProc())
			throw BAD_ACTIONSBEFORECREATEPROC;

		if(m_bcheckCRC)
			if(!CRCFile(victimFileName.c_str(), m_dwVictimCRCValue))
				throw BAD_CRCFILE;

		//If a commmandline is provided to the process passes it to the victim as well
		TextString commandline;
		int idx=1;
		if(argc!=NULL && argv!=NULL) {
			while(idx<argc) {
				if(argv[idx]!=NULL)
					commandline << argv[idx] << " ";
				idx++;
			}
		}
		if(commandline.length()>0)
			commandline[commandline.length()-1]='\0'; //eliminates the trailing space, to make it "perfect"
		
		//As MSDN reports, if lpApplicationName is NULL, the first white-space delimited 
		//token of the command line specifies the module name.
		TextString str;
		str << victimFileName << " " << commandline;
		if( !::CreateProcess( NULL, // No module name (use command line). 
			str.str(),				// Command line. 
			NULL,					// Process handle not inheritable. 
			NULL,					// Thread handle not inheritable. 
			NULL,					// Set handle inheritance to FALSE. 
			m_dwCreationFlags,		// suspended creation flags. 
			NULL,					// Use parent's environment block. 
			NULL,					// Use parent's starting directory. 
			&si,					// Pointer to STARTUPINFO structure.
			&pi )					// Pointer to PROCESS_INFORMATION structure.
			) 
		{
			throw BAD_CREATEPROCESS;
		}

		printf(m_startingMsg.c_str());
		#ifdef _DEBUG
		printf("ShubLoader is going to write %d bytes in the victim's process\n", stkPatches.size());
		#endif //_DEBUG

		if(!ActionsAfterCreateProc()) {
			CloseHandle(pi.hProcess);
			throw BAD_ACTIONSAFTERCREATEPROC;
		}

		//To resume the process is only OK for processes which are not debugged 
		if(m_dwCreationFlags == CREATE_SUSPENDED) {
			if(ResumeThread(pi.hThread)==-1) {
				CloseHandle(pi.hProcess);
				throw BAD_RESUMEPROCESS;
			}
		}
		
		//Main waiting loop, iterates till the gate condition has been found.
		while(!bCanPatchVictim) {
			
			//Eventually used to get the thread priority: if a thread has an high priority 
			//might not listen to our SuspendThread requests
			//if !=0 then has been set
			int thPriority=0;
			
			if(!ActionsBeforeGateProcedure()) {
				CloseHandle(pi.hProcess);
				throw BAD_ACTIONSBEFOREGATEPROCEDURE;
			}

			//Check the GateCondition.
			bCanPatchVictim=GateProcedure();

			//Do the work only if the window we searched has been found
			if(bCanPatchVictim) {

				#ifdef _DEBUG
				if(!m_SilentMode) {
					//Message that the patching process started..
					::MessageBox(NULL,"GateCondition reached",DEFAULT_MSG_CAPTION, 
						MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
				}
				#endif
				
				//Before patching the victim application it's better to suspend it..
				//If we cannot for some protection suspend the application then
				//a little of tentatives are tried:
				//1. repeat several time SuspendThread (see comment below to see why)
				//2. try to lower the priority
				//3. try using the kernel counterparts zwSuspendThread and zwSuspendProcess
				//4. open the process to get another process handle. 
				// If all these things fails then closes the patcher with an error!
				if(SuspendThread(pi.hThread)==-1) {
					//If the thread is making a kernel call, SuspendThread fails. 
					//An application may need to repeat the SuspendThread several times for it 
					//to succeed.
					int trials_count=0;
					BOOL skiptherest=FALSE;
					while(trials_count<=MAX_SUSPENDTHREAD_TRIALS) {
						if(SuspendThread(pi.hThread)!=-1) {
							skiptherest=TRUE;
							break;
						}
						trials_count++;
					}
					
					//Try to lower the the thread's priority.
					if(!skiptherest) {
						thPriority=GetThreadPriority(pi.hThread);
						if(thPriority!=THREAD_PRIORITY_NORMAL)
							SetThreadPriority(pi.hThread,THREAD_PRIORITY_NORMAL);
						if(SuspendThread(pi.hThread)!=-1)
							skiptherest=TRUE;
					}
					
					//Try suspending the process using kernel equivalent functions
					NTSTATUS ret=0;
					if(!skiptherest) {
						ret=ZwSuspendThread(pi.hThread, NULL);
						if(ret>=0)
							skiptherest=TRUE;
					}
					if(!skiptherest) {
						ret=ZwSuspendProcess(pi.hProcess);
						if(ret>=0)
							skiptherest=TRUE;
					}

					if(!skiptherest) {
						//All the other thing failed so much probably the handle you have it's still
						//not valid then it's time to open the process, using the m_ghMainWnd, found
						//using the GateProcedure(), which gives us access to the belonging ProcessId
						//the through OpenProcess we have another time a valid hProcess.
						//The only difference is that this time we must use zwSuspendProcess 
						//and zwResumeProcess undocumented ntdll exports, because we do not have 
						//a valid handle for the process's Treads.
						CloseHandle(pi.hProcess);
						memset(&pi, 0, sizeof(PROCESS_INFORMATION));
						DWORD dwProcessId=0;
						GetWindowThreadProcessId(m_ghMainWnd, &dwProcessId);
						HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessId);
						#ifdef _DEBUG
						if(!m_SilentMode) {
							char str[25];
							sprintf(str,"hProc=%x, dwProcessId=%d (%x)",hProc, dwProcessId,dwProcessId);
							::MessageBox(NULL, str, DEFAULT_MSG_CAPTION, MB_OK);
						}
						#endif
						if(hProc==NULL) {
							CloseHandle(pi.hProcess);
							throw BAD_SUSPENDPROCESS;
						}
						pi.hProcess=hProc;
						bProcessOpened=TRUE;
						NTSTATUS ret=ZwSuspendProcess(pi.hProcess);
						if(ret>=0)
							skiptherest=TRUE;
					}

					if(!skiptherest) {
						CloseHandle(pi.hProcess);
						throw BAD_SUSPENDPROCESS;
					}
						
				}
				//////////////////////////////////////////////////////////////////////////
								
				//Start the memory patching process. It uses the MBG_gsar class (see Oraculum's tutorial)
				BMG_gsar gsar;
				TextString strlastError;
				
				//for each patch do the whole work
				for (int idx=0; idx<NumberofPatches; idx++) {
					//This boolean is used to write or not the patched bytes
					//in case of mismatches between read and foreseen original bytes 
					//and if the patch byte is not set
					BOOL bDonotWrite=FALSE;
					//Used when, according to the constructor of Patch class, the bytes shouldn't be read
					//for example when only a function must be called and no other actions.
					BOOL bDonotRead=FALSE;
					
					//takes the top (last in) patch from the patches stack
					Patch ptc=stkPatches.top();

					//Properly set the DonotRead and DonotWrite flags
					if(ptc.OnlyDoCallback) {
						bDonotRead=bDonotWrite=TRUE;
					}

					//Read the original bytes from the victim process
					//The destination values are placed into the the Patch::orig
					//and the bytes read are places into Patch::bytesread
					//It is also performed a check of the just read memory byte, which should
					//be equal to the original byte already specified in the Patch object, if any.
					if(!bDonotRead) {
						BYTE orig=0;
						gsar.ReadProcessMemory(pi.hProcess,
							(LPVOID)(ptc.address), (LPVOID)(&(orig)), 1,
							&ptc.bytesread);
						if(ptc.bytesread==0)
							strlastError=GetLastErrorMsg();
						else 
							strlastError=TextString("OK");
					
						//If the Patch::checkorigByte flag is set and if there are mismatches between 
						//read and foreseen bytes, a proper message is formed and the flag which
						//avoid writing in memory is set.
						if(ptc.checkorigByte) {
							if(ptc.orig!=orig) {
								char msg[MAX_PATH];
								sprintf(msg, 
									"Error at Address %X: expected original byte %X differs from read byte %X",
									ptc.address, ptc.orig, orig);
								ptc.msg=TextString(msg);
								stkErrors.push(TextString(msg));
								bDonotWrite=TRUE;
							}
						}

						//the read value can be copied into the Patch data, because all the controls

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -