📄 debug.cpp
字号:
m_mapModule.RemoveKey ( lpAddress ) ;
delete p ;
}
void CDebugControl::EnableSingleStep ( Thread* pThread )
{
// set TF bit of CPU flag register
CONTEXT cnt ;
cnt.ContextFlags = CONTEXT_CONTROL ;
GetThreadContext ( pThread->m_hThread , &cnt ) ;
cnt.EFlags |= TF_FLAG ;
SetThreadContext ( pThread->m_hThread , &cnt ) ;
SuspendThreadExcept ( pThread ) ;
}
void CDebugControl::BackwardEip ( Thread* pThread )
{
// sub eip by one after encountering a breakpoint
CONTEXT cnt ;
cnt.ContextFlags = CONTEXT_CONTROL ;
GetThreadContext ( pThread->m_hThread , &cnt ) ;
cnt.Eip-- ;
SetThreadContext ( pThread->m_hThread , &cnt ) ;
FlushInstructionCache ( m_hProcess , NULL , 0 ) ;
}
// followings are helper function for safe-memory-read/write
BYTE CDebugControl::ReadByte ( LPVOID lpBase )
{
DWORD oldp = 0 ;
BYTE b = 0 ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
1 ,
PAGE_EXECUTE_READWRITE ,
&oldp ) ;
ReadProcessMemory (
m_hProcess ,
lpBase ,
&b ,
1 ,
NULL ) ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
1 ,
oldp ,
&oldp ) ;
return b ;
}
BOOL CDebugControl::ReadBlock ( LPVOID lpBase , LPVOID lpBuf , int size )
{
DWORD oldp = 0 , r;
ReadProcessMemory (
m_hProcess ,
lpBase ,
lpBuf ,
size ,
&r ) ;
return r == ( DWORD ) size ;
}
WORD CDebugControl::ReadWord ( LPVOID lpBase )
{
DWORD oldp = 0 ;
WORD w = 0 ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
2 ,
PAGE_EXECUTE_READWRITE ,
&oldp ) ;
ReadProcessMemory (
m_hProcess ,
lpBase ,
&w ,
2 ,
NULL ) ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
2 ,
oldp ,
&oldp ) ;
return w ;
}
DWORD CDebugControl::ReadDWord ( LPVOID lpBase )
{
DWORD dw = 0 , oldp = 0 ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
4 ,
PAGE_EXECUTE_READWRITE ,
&oldp ) ;
ReadProcessMemory (
m_hProcess ,
lpBase ,
&dw ,
4 ,
NULL ) ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
4 ,
oldp ,
&oldp ) ;
return dw ;
}
void CDebugControl::WriteByte ( LPVOID lpBase , BYTE b )
{
DWORD oldp = 0 ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
1 ,
PAGE_EXECUTE_READWRITE ,
&oldp ) ;
WriteProcessMemory (
m_hProcess ,
lpBase ,
&b ,
1 ,
NULL ) ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
1 ,
oldp ,
&oldp ) ;
}
void CDebugControl::WriteDWord ( LPVOID lpBase , DWORD dw )
{
DWORD oldp = 0 ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
4 ,
PAGE_EXECUTE_READWRITE ,
&oldp ) ;
WriteProcessMemory (
m_hProcess ,
lpBase ,
&dw ,
4 ,
NULL ) ;
VirtualProtectEx (
m_hProcess ,
lpBase ,
4 ,
oldp ,
&oldp ) ;
}
void CDebugControl::ReadString ( LPVOID lpBase , CString& str )
{
BYTE b ;
DWORD addr = ( DWORD ) lpBase ;
str.Empty ( ) ;
while ( b = ReadByte ( ( LPVOID ) addr ) )
{
str += ( CHAR ) b ;
addr++ ;
}
}
void CDebugControl::ReadStringW ( LPVOID lpBase , CString& str )
{
WORD w ;
DWORD addr = ( DWORD ) lpBase ;
str.Empty ( ) ;
while ( w = ReadWord ( ( LPVOID ) addr ) )
{
str += ( CHAR ) w ;
addr += 2 ;
}
}
DWORD CDebugControl::GetRegister ( Thread* pThread , DWORD dwID )
{
CONTEXT cnt ;
cnt.ContextFlags = CONTEXT_FULL ;
GetThreadContext ( pThread->m_hThread , &cnt ) ;
switch ( dwID )
{
case EAX : return cnt.Eax ;
case EBX : return cnt.Ebx ;
case ECX : return cnt.Ecx ;
case EDX : return cnt.Edx ;
case ESP : return cnt.Esp ;
case EBP : return cnt.Ebp ;
case ESI : return cnt.Esi ;
case EDI : return cnt.Edi ;
case EIP : return cnt.Eip ;
}
// no more register !
ASSERT ( FALSE ) ;
return 0 ;
}
void CDebugControl::SetRegister ( Thread* pThread , DWORD dwID , DWORD v )
{
CONTEXT cnt ;
cnt.ContextFlags = CONTEXT_FULL ;
GetThreadContext ( pThread->m_hThread , &cnt ) ;
switch ( dwID )
{
case EAX : cnt.Eax = v ; break ;
case EBX : cnt.Ebx = v ; break ;
case ECX : cnt.Ecx = v ; break ;
case EDX : cnt.Edx = v ; break ;
case EBP : cnt.Ebp = v ; break ;
case ESP : cnt.Esp = v ; break ;
case ESI : cnt.Esi = v ; break ;
case EDI : cnt.Edi = v ; break ;
case EIP : cnt.Eip = v ; break ;
}
SetThreadContext ( pThread->m_hThread , &cnt ) ;
if ( dwID == EIP ) // muse flush instruction cache after eip is changed
FlushInstructionCache ( m_hProcess , NULL , 0 ) ;
}
DWORD CDebugControl::GetParameter ( Thread* pThread , DWORD dwIndex )
{
DWORD esp = GetRegister ( pThread , ESP ) ;
return ReadDWord ( ( LPVOID ) ( esp + 4 * ( dwIndex + 1 ) ) ) ;
}
BOOL CDebugControl::OnBreakpoint ( DWORD dwID , EXCEPTION_RECORD& v ) // auto process logic
{
Thread* pt = ( Thread* ) QueryThread ( dwID ) ;
ASSERT ( pt != NULL ) ;
Breakpoint* pb = QueryBreakpoint ( v.ExceptionAddress ) ;
if ( pb == NULL ) // additional breakpoints
{
if ( ( DWORD ) m_lpMem <= ( DWORD ) v.ExceptionAddress &&
( DWORD ) v.ExceptionAddress < ( DWORD ) m_lpMem + m_arHooked.GetSize ( ) * 8 )
{
// in a stub code
DWORD ind = ( ( DWORD ) v.ExceptionAddress - ( DWORD ) m_lpMem ) / 8 ; // get index
OnStubNotify ( pt , ind ) ;
// set a breakpoint at return address
StopAtReturn ( pt , ( Breakpoint* ) ( 0x80000000 | ind ) ) ;
return TRUE ;
}
return FALSE ;
}
// pass this breakpoint
PassBreakpoint ( pt , pb ) ;
return TRUE ;
}
BOOL CDebugControl::OnSingleStep ( DWORD dwID , EXCEPTION_RECORD& v )
{
// after single-step , restore last breakpoint
Thread* pt = QueryThread ( dwID ) ;
ASSERT ( pt != NULL ) ;
if ( pt->m_pLastBreakpoint == NULL )
return FALSE ;
Breakpoint* pb = pt->m_pLastBreakpoint ;
pt->m_pLastBreakpoint = NULL ;
WriteByte ( pb->m_lpAddress , INT3 ) ;
// let other threads go
ResumeThreadExcept ( pt ) ;
return TRUE ;
}
Breakpoint* CDebugControl::AddBreakpoint ( Thread* pThread , LPVOID lpAddress )
{
Breakpoint* p = QueryBreakpoint ( lpAddress ) ;
if ( p == NULL ) // breakpoint not found - not set yet
{
p = new Breakpoint ;
p->m_lpAddress = lpAddress ;
p->m_byteCode = ReadByte ( lpAddress ) ;
p->m_bLimit = TRUE ;
WriteByte ( lpAddress , INT3 ) ;
m_arBreakpoint.Add ( p ) ;
m_mapBreakpoint [ lpAddress ] = p ;
}
p->m_arRefThread.Add ( pThread->m_dwID ) ;
return p ;
}
// additional breakpoint - always vailable
void CDebugControl::AddUnlimitedBreakpoint ( LPVOID lpAddress )
{
Breakpoint* p = new Breakpoint ;
p->m_lpAddress = lpAddress ;
p->m_byteCode = ReadByte ( lpAddress ) ;
p->m_bLimit = FALSE ;
WriteByte ( lpAddress , INT3 ) ;
m_arBreakpoint.Add ( p ) ;
m_mapBreakpoint [ lpAddress ] = p ;
}
Breakpoint* CDebugControl::QueryBreakpoint ( LPVOID lpAddress )
{
LPVOID p ;
if ( m_mapBreakpoint.Lookup ( lpAddress , p ) == FALSE )
return NULL ;
return ( Breakpoint* ) p ;
}
void CDebugControl::PassBreakpoint ( Thread* pThread , Breakpoint* pBreakpoint )
{
// restore breakpoint code
WriteByte ( pBreakpoint->m_lpAddress , pBreakpoint->m_byteCode );
BackwardEip ( pThread ) ;
if ( pBreakpoint->m_bLimit == FALSE ) // not limited - normal temp breakpoint
{
PreDispatch ( pThread , pBreakpoint ) ;
EnableSingleStep ( pThread ) ;
pThread->m_pLastBreakpoint = pBreakpoint ;
StopAtReturn ( pThread , pBreakpoint ) ;
}
BOOL f = FALSE ;
for ( ; ; )
{
int i , n = pBreakpoint->m_arRefThread.GetSize ( ) ;
for ( i = n - 1 ; i >= 0 ; i++ )
{
Thread* p = QueryThread ( pBreakpoint->m_arRefThread [ i ] ) ;
if ( p->m_dwID == pThread->m_dwID)
{
f = TRUE ;
break ;
}
}
if ( f == TRUE )
{
PostDispatch ( pThread ) ;
pBreakpoint->m_arRefThread.RemoveAt ( i ) ;
if ( pBreakpoint->m_bLimit == TRUE &&
pBreakpoint->m_arRefThread.GetSize ( ) == 0 ) // no reference
{
// remove breakpoint from internal data
REMOVE_IN_PTR_ARRAY ( m_arBreakpoint , pBreakpoint ) ;
m_mapBreakpoint.RemoveKey ( pBreakpoint->m_lpAddress ) ;
delete pBreakpoint ;
return ;
}
}
else break ;
}
// need single-step debugging
if ( pBreakpoint->m_bLimit == TRUE )
{
EnableSingleStep ( pThread ) ;
pThread->m_pLastBreakpoint = pBreakpoint ;
}
}
void CDebugControl::StopAtReturn ( Thread* pThread , Breakpoint* pBreakpoint )
{
LPVOID addr = ( LPVOID )
ReadDWord ( ( LPVOID ) GetRegister ( pThread , ESP ) ) ;
AddBreakpoint ( pThread , addr ) ;
pThread->m_stBreakpoint.AddTail ( pBreakpoint ) ; // associated with a single thread
}
void CDebugControl::SnapModule ( )
{
MODULEINFO mi ;
CHAR buf [ MAX_PATH ] ;
int i , n = m_arModule.GetSize ( ) ;
for ( i = 0 ; i < n ; i++ )
{
Module2* p = ( Module2* ) m_arModule [ i ] ;
if ( p->m_dwSize != 0 ) continue ;
if ( TRUE == GetModuleInformation ( // get information about this module
m_hProcess ,
( HMODULE ) p->m_lpBase ,
&mi ,
sizeof ( MODULEINFO ) ) )
{
GetModuleFileNameEx (
m_hProcess ,
( HMODULE ) p->m_lpBase ,
buf ,
MAX_PATH ) ;
p->m_strPathName = buf ;
p->m_dwSize = mi.SizeOfImage ;
if ( i != 0 )
{
CString msg ;
msg.Format (
IDS_DEBUG_LOAD_DLL ,
p->m_strPathName ,
p->m_lpBase ,
( DWORD ) p->m_lpBase + p->m_dwSize ) ;
m_pDancerDoc->m_pRecordManager->AddDebugMsg ( msg , 0 ) ;
}
PatchModule ( p ) ; // patch this moudle to install hooks
}
}
}
void CDebugControl::PreDispatch ( Thread* pThread , Breakpoint* pBreakpoint )
{
CMainApp* p = ( CMainApp* ) AfxGetApp ( ) ;
if ( p->m_pfnGetProcAddress == pBreakpoint->m_lpAddress )
{
LPVOID addr = ( LPVOID ) GetParameter ( pThread , 1 ) ,
base1 = ( LPVOID ) GetReturnAddress ( pThread ) ,
base2 = ( LPVOID ) GetParameter ( pThread , 0 ) ;
WORD n ;
Module2* pm1 = QueryModule ( base1 ) ,
*pm2 = QueryModule ( base2 ) ;
BOOL f = FALSE ;
while ( pm1 == NULL || pm2 == NULL ||
pm1->m_dwSize == 0 || pm2->m_dwSize == 0 )
{
SnapModule ( ) ;
pm1 = QueryModule ( base1 ) ;
pm2 = QueryModule ( base2 ) ;
if ( f == FALSE ) f = TRUE ;
else break ;
}
if ( pm1 == NULL || pm2 == NULL ||
pm1->m_dwSize == 0 || pm2->m_dwSize == 0 )
{
pThread->m_stDelay.AddTail ( -1 ) ;
return ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -