利用DEBUG API编写Loader Path

    Loader并不是什么很神秘的技术,微软提供了一组Debug Api来方便第三方监视程序.这里我用Debug Api制作了一个简单的Loader程序.
   这个Loader要干的事有:
   1.启动目标程序.
   2.读取/修改目标程序的内存 或 寄存器
   用到的Debug Api有:
  CreateProcess —— 用于创建被调试进程
  WaitForDebugEvent —— Debug Loop(调试循环)的主要构成函数
  ContinueDebugEvent —— 用于构成Debug Loop
  GetThreadContext —— 得到被调试进程的寄存器信息
  SetThreadContext —— 设置被调试进程的寄存器信息
  ReadProcessMemory —— 得到被调试进程的内存内容
  WriteProcessMemory —— 设置被调试进程的内存内容

   相应的数据结构如下
  CONTEXT —— 寄存器结构
  STARTUPINFO —— Start信息
  PROCESS_INFORMATION —— 进程相关信息
  DEBUG_EVENT —— Debug Event(调试事件)结构
   Loader具体代码如下:
//  MemoryReader.cpp : 定义控制台应用程序的入口点。
//  AntiDebug:IsDebugPresent如何避开?
//  加壳处理不完善
//

#include 
" stdafx.h "
#include 
" windows.h "
#include 
" Commdlg.h "
#include 
" winnt.h "

BYTE INT3 
=   0xCC ;

// 写入前的
BYTE Old;

// 页面属性
DWORD OldProtect;

// 是否已写入INT3
bool  HasINT3  =   false ;

bool  IsFirstINT3  =   true ;

DWORD BreakPoint 
=   0x00452191 ;

BYTE Org[
8 =  { 0xE8 , 0x4E };

// 判断是否解压完成
bool  IsUnpacked(PROCESS_INFORMATION pi)
{
    SuspendThread(pi.hThread);
    CONTEXT context;
    ZeroMemory(
& context, sizeof (CONTEXT));
    context.ContextFlags 
=  CONTEXT_FULL  |  CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(pi.hThread,
& context);
    printf(
" Exe Info:Eax:%x,Esp:%x,Eip:%x\n " ,context.Eax,context.Esp,context.Eip);        
    ResumeThread(pi.hThread);
    BYTE mem[
8 ];
    VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,PAGE_READWRITE,  & OldProtect);
    ReadProcessMemory(pi.hProcess,(LPCVOID)BreakPoint,
& mem, 8 ,NULL);
    VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,OldProtect, & OldProtect);
    printf(
" hex num is:%x,%x,%x,%x\n " ,mem[ 0 ],mem[ 1 ],mem[ 2 ],mem[ 3 ]);
    
if (mem[ 0 ^   0xff   ==  Org[ 0 &&  mem[ 1 ^   0xff   ==  Org[ 1 ])
    {
        
// 不能乱调用
        Old  =  mem[ 0 ];
        
return  TRUE;
    }
    
return   false ;
}

// 写INT3
bool  WriteINT3(PROCESS_INFORMATION pi)
{
    
// VirtualAllocEx(pi.hProcess,(LPVOID)0x0101259b,sizeof(INT3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    SuspendThread(pi.hThread);
    VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,PAGE_READWRITE,  & OldProtect);
    
bool  ret  =  WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & INT3, sizeof (INT3),NULL);
    VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,OldProtect, & OldProtect);
    HasINT3 
=  ret;
    ResumeThread(pi.hThread);
    
return  ret;
}

// 改回去
bool  CleanINT3(PROCESS_INFORMATION pi)
{
    
// SuspendThread(pi.hThread);
     bool  ret  =  WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & Old, sizeof (Old),NULL);
    
if (ret  ==   false )
    {
        printf(
" 改回去失败!\n " );
    }
    CONTEXT context;
    ZeroMemory(
& context, sizeof (CONTEXT));
    context.ContextFlags 
=  CONTEXT_FULL  |  CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(pi.hThread,
& context);
    context.Eip
-- ;
    SetThreadContext(pi.hThread,
& context);

    printf(
" 已经改回去了,Eax:%x\n " ,context.Eax);
    
return  ret;
}

// 隐藏Debug
void  HideDebug(PROCESS_INFORMATION pi)
{
    BYTE ISDEBUGFLAG 
=   0x00 ;
    
int  ISHEAPFLAG  =   2 ;
    SuspendThread(pi.hThread);
    CONTEXT context;
    ZeroMemory(
& context, sizeof (CONTEXT));
    context.ContextFlags 
=  CONTEXT_FULL  |  CONTEXT_DEBUG_REGISTERS;
    GetThreadContext(pi.hThread,
& context);
    
// IsDebugPresent_Flag
    WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x2 ), & ISDEBUGFLAG, 1 ,NULL);
    
// NTGlobal_Flag  用0D则为70  这个为0 防止其他调试器存在
    WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x68 ), & ISDEBUGFLAG, 1 ,NULL);
    
// GetProcessHeap_Flag
    DWORD HeapAddress;
    ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx 
+   0x18 ), & HeapAddress, sizeof (HeapAddress),NULL);
    WriteProcessMemory(pi.hProcess,(LPVOID)HeapAddress,
& ISHEAPFLAG, sizeof (ISHEAPFLAG),NULL);

    ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx 
+   0x68 ), & ISDEBUGFLAG, 1 ,NULL);
    printf(
" NT_GLOBAL=%d\n " ,ISDEBUGFLAG);
    ResumeThread(pi.hThread);
}


int  main( int  argc,  char *  argv[])
{
    
char  f_name[ 256 ];
    f_name[
0 =  NULL;
    OPENFILENAME filename;
    ZeroMemory(
& filename, sizeof (OPENFILENAME));
    filename.lStructSize 
=   sizeof (OPENFILENAME);
    filename.hwndOwner 
=  NULL;
    filename.lpstrFilter 
=   " *.exe " ;
    filename.lpstrFile 
=  f_name;
    filename.nMaxFile 
=   256 ;
    filename.lpstrInitialDir 
=  NULL;
    filename.Flags 
=  OFN_EXPLORER  |  OFN_HIDEREADONLY;
    
if ( ! GetOpenFileName( & filename))
        
return   0 ;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(
& si, sizeof (STARTUPINFO));
    ZeroMemory(
& pi, sizeof (PROCESS_INFORMATION));
    
bool  ret  =  CreateProcess(filename.lpstrFile, "" ,NULL,NULL,FALSE,DEBUG_PROCESS,NULL,NULL, & si, & pi);
    
if (ret  ==   false )
    {
        MessageBox(NULL,
" 创建进程失败! " , "" , 0 );
        
return   - 1 ;
    }

    
// Anti-Anti-Debug
    HideDebug(pi);

    DEBUG_EVENT devent;
    
int  DllCount  =   0 ;
    
while (TRUE)
    {
        
if (WaitForDebugEvent( & devent, 1 ))
        {
            
switch (devent.dwDebugEventCode)
            {
            
case  CREATE_PROCESS_DEBUG_EVENT:
                printf(
" CREATE_PROCESS_DEBUG_EVENTdot.gif\n " );
                
break ;
            
case  CREATE_THREAD_DEBUG_EVENT:
                printf(
" CREATE_THREAD_DEBUG_EVENTdot.gif\n " );
                
break ;
            
case  EXCEPTION_DEBUG_EVENT:
                
// printf("EXCEPTION_DEBUG_EVENTdot.gif\n");
                  switch (devent.u.Exception.ExceptionRecord.ExceptionCode)
                {
                
case  EXCEPTION_BREAKPOINT:
                    
if (HasINT3)
                    {    
                        SuspendThread(pi.hThread);
                        CONTEXT context;
                        ZeroMemory(
& context, sizeof (CONTEXT));
                        context.ContextFlags 
=  CONTEXT_FULL  |  CONTEXT_DEBUG_REGISTERS;
                        GetThreadContext(pi.hThread,
& context);
                        printf(
" Eax:%x\n,Esi:%x\n,Eip:%x\n,Ebp:%x\n " ,context.Eax,context.Esi,context.Eip,context.Ebp); 
                        
if (context.Eip  ==  BreakPoint  +   1 )
                        {
                            
if ( ! CleanINT3(pi))
                            {
                                printf(
" 清除断点失败! " );
                            }

                            printf(
" Program Stopped At What We Want\n " );
                            
char  key[ 256 ];

                            VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,PAGE_READWRITE,  & OldProtect);
                            ReadProcessMemory(pi.hProcess,(LPCVOID)context.Edx,key,
sizeof (key),NULL);
                            VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,
1 ,OldProtect, & OldProtect);
                            
                            printf(
" 读出来的东西是 %s\n " ,key);        
                        }
                        ResumeThread(pi.hThread);
                    }    
                    
break ;
                
case  EXCEPTION_SINGLE_STEP:
                    printf(
" 2 EXCEPTION_SINGLE_STEP\n " );
                    
break ;
                
case  EXCEPTION_ACCESS_VIOLATION:
                    printf(
" 读写地址出错\n " );
                    printf(
" %d,%x\n " ,devent.u.Exception.ExceptionRecord.ExceptionInformation[ 0 ],devent.u.Exception.ExceptionRecord.ExceptionAddress);

                    ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);

/*                     char Nop[3];
                    Nop[0] = 0x90;
                    Nop[1] = 0x90;
                    Nop[2] = 0x90;
                    PVOID pathAddress;
                    pathAddress = devent.u.Exception.ExceptionRecord.ExceptionAddress;
                    VirtualProtectEx(pi.hProcess,pathAddress,3,PAGE_READWRITE, &OldProtect);
                    WriteProcessMemory(pi.hProcess,pathAddress,Nop,3,NULL);
                    VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,1,OldProtect,&OldProtect);

                    ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);        
*/         
                    
break ;
                
default :
                    
break ;
                }
                
break ;
            
case  LOAD_DLL_DEBUG_EVENT:
                
// 获取DLL NAME太复杂,暂时做不到
                DllCount  ++ ;
                printf(
" %d,Program Loads a Dll From BaseImage:%x,ImageName:%x\n " ,DllCount,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);                
                
if ( ! HasINT3)
                {
                  
if (IsUnpacked(pi))
                  {
                      printf(
" UnPacked Success!!\n " );
                      WriteINT3(pi);
                      printf(
" Write a INT3\n " );
                  }
                }
                
break ;
            
case  UNLOAD_DLL_DEBUG_EVENT:
                printf(
" UnLoad a Dll From BaseImage:%x,ImageName:%x\n " ,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);                
                
if ( ! HasINT3)
                {
                  
if (IsUnpacked(pi))
                  {
                      printf(
" UnPacked Success!!\n " );
                      WriteINT3(pi);
                      printf(
" Write a INT3\n " );
                  }
                }
                
break ;
            
case  OUTPUT_DEBUG_STRING_EVENT:
                
break ;
            
case  EXIT_PROCESS_DEBUG_EVENT:
                printf(
" 调试程序已退出 " );
                
break ;
            
default :
                printf(
" %d\n " ,devent.dwDebugEventCode);
                
break ;
            }
            ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_CONTINUE);
        }
        
else
        {
        }
    }
    
// KeyMake中不要这两句
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    
return   0 ;
}


       目前版本功能:
      1.启动目标程序
      2.向指定位置写入INT3断点
      3.读取/设置指定位置寄存器值
      4.读取/修改指定位置内存值
      5.解压一些压缩和加密壳
      6.一些Anti-Anti-Debug功能

转载于:https://www.cnblogs.com/Red_angelX/archive/2007/05/08/738552.html

你可能感兴趣的:(利用DEBUG API编写Loader Path)