📄 debug.cpp
字号:
#include "pch.h"
#include "util.h"
#include "main.h"
#include "doc.h"
#include "debug.h"
#include "type.h"
#include "record.h"
Record::Record ( )
{
}
Record::~Record ( )
{
if ( m_nType == HOOK_MSG &&
m_pDispatch->m_bPending == FALSE ) // this call is finished
delete m_pDispatch ;
}
void Record::Present ( CString& msg ) // output to a string
{
if ( m_nType != HOOK_MSG )
{
xTranslateTime ( m_dwTime , msg ) ;
msg += ' ' ;
msg += m_strMsg ;
}
else
{
if ( m_pDispatch->m_bHasName == TRUE )
{
msg = m_pDispatch->m_strFunction ;
}
else msg.Format ( "0x%08x" , m_pDispatch->m_wOrdinal ) ;
}
}
void Record::Present2 ( CString& msg ) // another output function
{
CString str ;
msg = m_pDispatch->m_strImportName ;
msg += " - " ;
if ( m_pDispatch->m_bHasName == TRUE )
{
msg += m_pDispatch->m_strFunction ;
}
else
{
str.Format ( "0x%08x" , m_pDispatch->m_wOrdinal ) ;
msg += str ;
}
msg += '!' ;
msg += m_pDispatch->m_strExportName ;
}
Thread::Thread ( )
{
m_hThread = NULL ;
m_pLastBreakpoint = NULL ;
m_dwDepth = 0 ;
}
Thread::~Thread ( )
{
}
CDebugControl::CDebugControl ( )
{
m_bDebugging = FALSE ;
m_bPause = FALSE ;
InitializeCriticalSection ( &m_csSync ) ;
}
CDebugControl::~CDebugControl ( )
{
if ( m_bDebugging == TRUE )
Stop ( ) ;
DeleteCriticalSection ( &m_csSync ) ;
}
void CDebugControl::AttachTo ( CDancerDoc* pDancerDoc )
{
m_pDancerDoc = pDancerDoc ;
}
void CDebugControl::Start ( )
{
PreProcess ( ) ;
m_pDebugThread = AfxBeginThread ( DebugThread , this ) ; // create debug thread
}
void CDebugControl::Stop ( )
{
TerminateProcess ( m_hProcess , -1 ) ;
}
void CDebugControl::PreProcess ( )
{
// reset internal data
m_bDebugging = TRUE ;
m_bPause = FALSE ;
m_bInitialBreakpoint = TRUE ;
m_bExited = FALSE ;
m_pDancerDoc->m_pImgFile->GetHooked ( m_arHooked ) ;
// load type information
m_pDancerDoc->m_pRecordManager->Start ( ) ;
m_pTypeManager = new CTypeManager ;
m_pTypeManager->AttachTo ( this ) ;
m_pTypeManager->LoadType ( m_arHooked ) ;
m_pTypeManager->LoadDecoder ( ) ;
}
void CDebugControl::PostProcess ( )
{
m_bDebugging = FALSE ;
m_bPause = FALSE ;
// prepare for all safe attribute ( reset )
RELEASE_PTR_ARRAY ( m_arThread , Thread ) ;
RELEASE_PTR_ARRAY ( m_arModule , Module2 ) ;
RELEASE_PTR_ARRAY ( m_arHooked , Hooked ) ;
RELEASE_PTR_ARRAY ( m_arBreakpoint , Breakpoint ) ;
m_mapBreakpoint.RemoveAll ( ) ;
m_mapModule.RemoveAll ( ) ;
m_mapThread.RemoveAll ( ) ;
m_pDancerDoc->m_pRecordManager->Stop ( ) ;
m_pTypeManager->UnloadDecoder ( ) ;
if ( m_pTypeManager != NULL )
{
delete m_pTypeManager ;
m_pTypeManager = NULL ;
}
}
UINT CDebugControl::DebugThread ( LPVOID lpParam ) // debug core
{
TRY
{
CDebugControl* p = ( CDebugControl* ) lpParam ;
CString pn = p->m_pDancerDoc->GetPathName ( ) ;
pn += ' ' ;
pn += p->m_pDancerDoc->m_strParameter ;
STARTUPINFO si ;
PROCESS_INFORMATION pi ;
ZeroMemory ( &si , sizeof ( STARTUPINFO ) ) ;
si.cb = sizeof ( STARTUPINFO ) ;
// create target process and get ready
BOOL ret = CreateProcess (
NULL ,
pn.LockBuffer ( ) ,
NULL ,
NULL ,
FALSE ,
DEBUG_ONLY_THIS_PROCESS ,
NULL ,
p->m_pDancerDoc->m_strPath ,
&si ,
&pi ) ;
pn.UnlockBuffer ( ) ;
if ( ret == TRUE )
{
DEBUG_EVENT de ;
DWORD ret ;
BOOL fTimeout ;
CloseHandle ( pi.hThread ) ;
CloseHandle ( pi.hProcess ) ;
p->m_dwProcessID = pi.dwProcessId ;
for ( ; ; )
{
for ( ; ; )
{
fTimeout = !WaitForDebugEvent ( &de , UPDATE_INTERVAL_TIME ) ;
if ( fTimeout ) // time out
{
p->SnapModule ( ) ;
p->m_pDancerDoc->m_pRecordManager->Update ( ) ;
}
else break ;
}
// dispatch debug events
switch ( de.dwDebugEventCode )
{
case CREATE_PROCESS_DEBUG_EVENT :
ret = p->OnCreateProcess ( de.dwThreadId , de.u.CreateProcessInfo ) ;
break ;
case EXIT_PROCESS_DEBUG_EVENT :
ret = p->OnExitProcess ( de.dwThreadId , de.u.ExitProcess ) ;
break ;
case CREATE_THREAD_DEBUG_EVENT :
ret = p->OnCreateThread ( de.dwThreadId , de.u.CreateThread ) ;
break ;
case EXIT_THREAD_DEBUG_EVENT :
ret = p->OnExitThread ( de.dwThreadId , de.u.ExitThread ) ;
break ;
case EXCEPTION_DEBUG_EVENT :
ret = p->OnException ( de.dwThreadId , de.u.Exception ) ;
break ;
case LOAD_DLL_DEBUG_EVENT :
ret = p->OnLoadDll ( de.u.LoadDll ) ;
break ;
case UNLOAD_DLL_DEBUG_EVENT :
ret = p->OnUnloadDll ( de.u.UnloadDll ) ;
break ;
}
ContinueDebugEvent ( de.dwProcessId , de.dwThreadId , ret ) ;
if ( de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT )
break ;
}
}
p->PostProcess ( ) ; // terminate
}
CATCH_ALL ( CException )
{
// should not come here !
}
END_CATCH_ALL ;
return 0 ;
}
DWORD CDebugControl::OnCreateProcess ( DWORD dwID , CREATE_PROCESS_DEBUG_INFO& v )
{
m_hProcess = v.hProcess ;
AddThread ( dwID , v.lpStartAddress , v.hThread ) ;
AddModule ( v.lpBaseOfImage ) ;
CloseHandle ( v.hFile ) ;
// send debug message
CString msg ;
msg.Format ( IDS_DEBUG_CREATE_PROCESS , m_dwProcessID , v.lpBaseOfImage ) ;
m_pDancerDoc->m_pRecordManager->AddDebugMsg ( msg , 0 ) ;
return DBG_CONTINUE ;
}
DWORD CDebugControl::OnExitProcess ( DWORD dwID , EXIT_PROCESS_DEBUG_INFO& v )
{
// send debug message
CString msg ;
msg.Format ( IDS_DEBUG_EXIT_PROCESS , dwID , v.dwExitCode ) ;
m_pDancerDoc->m_pRecordManager->AddDebugMsg ( msg , 0 ) ;
RemoveThread ( dwID ) ;
int i , n = m_arModule.GetSize ( ) ;
for ( i = 0 ; i < n ; i++ )
{
Module2* pModule = ( Module2* ) m_arModule [ i ] ;
delete pModule ;
}
m_mapModule.RemoveAll ( ) ;
m_mapThread.RemoveAll ( ) ;
m_arModule.RemoveAll ( ) ;
m_arThread.RemoveAll ( ) ;
CloseHandle ( m_hProcess ) ;
return DBG_CONTINUE ;
}
DWORD CDebugControl::OnCreateThread ( DWORD dwID , CREATE_THREAD_DEBUG_INFO& v )
{
AddThread ( dwID , v.lpStartAddress , v.hThread ) ;
NotifyCreateThread ( dwID , v.lpStartAddress ) ;
return DBG_CONTINUE ;
}
DWORD CDebugControl::OnExitThread ( DWORD dwID , EXIT_THREAD_DEBUG_INFO& v )
{
RemoveThread ( dwID ) ;
// send debug message
CString msg ;
msg.Format ( IDS_DEBUG_EXIT_THREAD , dwID , v.dwExitCode ) ;
m_pDancerDoc->m_pRecordManager->AddDebugMsg ( msg , 0 ) ;
return DBG_CONTINUE ;
}
DWORD CDebugControl::OnException ( DWORD dwID , EXCEPTION_DEBUG_INFO& v )
{
if ( m_bInitialBreakpoint == TRUE )
{
// prepare stub code
int i , n = m_arHooked.GetSize ( ) ;
m_lpMem = VirtualAllocEx (
m_hProcess ,
NULL ,
n * 8 ,
MEM_COMMIT ,
PAGE_EXECUTE_READWRITE ) ;
for ( i = 0; i < n ; i++ )
{
WriteByte ( ( LPVOID ) ( ( DWORD ) m_lpMem + 8 * i ) , INT3 ) ;
WriteByte ( ( LPVOID ) ( ( DWORD ) m_lpMem + 8 * i + 1 ) , JMP ) ;
WriteDWord ( ( LPVOID ) ( ( DWORD ) m_lpMem + 8 * i + 2 ) , 0 ) ;
}
// hook additional functions , which is needed for me not user
CMainApp* p = ( CMainApp* ) AfxGetApp ( ) ;
if ( p->m_appOption.m_bHookExplicit == TRUE )
{
AddUnlimitedBreakpoint ( p->m_pfnGetProcAddress ) ; // break at GetProcAddress
AddUnlimitedBreakpoint ( p->m_pfnLoadLibraryExW ) ; // break at LoadLibraryExW
}
if ( p->m_appOption.m_bCheckDebugger == TRUE )
{
AddUnlimitedBreakpoint ( p->m_pfnIsDebuggerPresent ) ; // break at IsDebuggerPresent
}
SnapModule ( ) ; // catch all modules
CMainFrame* pf = ( CMainFrame* ) AfxGetMainWnd ( ) ;
pf->SetMessageText ( AFX_IDS_IDLEMESSAGE ) ;
Thread* pt = ( Thread* ) m_arThread [ 0 ] ;
NotifyCreateThread ( pt->m_dwID , pt->m_lpStartAddress ) ;
m_bInitialBreakpoint = FALSE ;
return DBG_CONTINUE ;
}
// continue dispatching
if ( v.dwFirstChance != 0 ) // first chance
{
if ( v.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT )
{
if ( OnBreakpoint ( dwID , v.ExceptionRecord ) == TRUE )
return DBG_CONTINUE ;
}
else if ( v.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP )
{
if ( OnSingleStep ( dwID , v.ExceptionRecord ) == TRUE )
return DBG_CONTINUE ;
}
}
else // second chance , target is error !
{
CString msg ;
msg.Format (
IDS_BAD_EXCEPTION ,
v.ExceptionRecord.ExceptionCode ,
v.ExceptionRecord.ExceptionAddress ) ;
AfxMessageBox ( msg , MB_ICONSTOP ) ;
}
return DBG_EXCEPTION_NOT_HANDLED ;
}
DWORD CDebugControl::OnLoadDll ( LOAD_DLL_DEBUG_INFO& v )
{
AddModule ( v.lpBaseOfDll ) ;
CloseHandle ( v.hFile ) ;
return DBG_CONTINUE ;
}
DWORD CDebugControl::OnUnloadDll ( UNLOAD_DLL_DEBUG_INFO& v )
{
// refresh all modules
Module2* pm = QueryModule ( v.lpBaseOfDll ) ;
if ( pm == NULL )
{
SnapModule ( ) ;
pm = QueryModule ( v.lpBaseOfDll ) ;
}
if ( pm != NULL )
{
CString msg ;
msg.Format ( IDS_DEBUG_UNLOAD_DLL , pm->m_strPathName ) ;
m_pDancerDoc->m_pRecordManager->AddDebugMsg ( msg , 0 ) ;
}
RemoveModule ( v.lpBaseOfDll ) ;
return DBG_CONTINUE ;
}
void CDebugControl::AddThread ( DWORD dwID , LPVOID lpStartAddress , HANDLE hThread )
{
Thread* p = new Thread ;
p->m_dwID = dwID ;
p->m_lpStartAddress = lpStartAddress ;
p->m_hThread = hThread ;
m_arThread.Add ( p ) ;
m_mapThread [ ( LPVOID ) dwID ] = p ; // map it
}
Thread* CDebugControl::QueryThread ( DWORD dwID )
{
LPVOID p ;
if ( m_mapThread.Lookup ( ( LPVOID ) dwID , p ) == FALSE )
return NULL ;
return ( Thread* ) p ;
}
void CDebugControl::RemoveThread ( DWORD dwID )
{
Thread* p = QueryThread ( dwID ) ;
ASSERT ( p != NULL ) ;
REMOVE_IN_PTR_ARRAY ( m_arThread , p ) ;
m_mapThread.RemoveKey ( ( LPVOID ) dwID ) ;
CloseHandle ( p->m_hThread ) ;
delete p ;
}
void CDebugControl::AddModule ( LPVOID lpBase )
{
Module2* p = new Module2 ;
p->m_lpBase = lpBase ;
p->m_dwSize = 0 ;
m_arModule.Add ( p ) ;
m_mapModule [ lpBase ] = p ; // map it
}
Module2* CDebugControl::QueryModule ( LPVOID lpAddress )
{
if ( lpAddress == NULL ) // get the main module - the first one
return ( Module2* ) m_arModule [ 0 ] ;
LPVOID p ;
if ( m_mapModule.Lookup ( lpAddress , p ) == FALSE )
{
DWORD e1 , e2 ;
int i , n = m_arModule.GetSize ( ) ;
for ( i = 0 ; i < n ; i++ )
{
Module2* p = ( Module2* ) m_arModule [ i ] ;
e1 = ( DWORD ) p->m_lpBase ;
e2 = e1 + p->m_dwSize ;
if ( e1 <= ( DWORD ) lpAddress &&
e2 > ( DWORD ) lpAddress )
return p ;
}
return NULL ; // nothing matched
}
return ( Module2* ) p ;
}
void CDebugControl::RemoveModule ( LPVOID lpAddress )
{
Module2* p = QueryModule ( lpAddress ) ;
if ( p == NULL ) return ;
REMOVE_IN_PTR_ARRAY ( m_arModule , p ) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -