使用C语言hook send函数

(注:非前端知识)

C语言代码,原理非常简单,把一个dll文件注入到程序,dll通过修改send函数的入口指令跳转到我的函数,当程序发送数据时,建立文件D:\\a.txt,把发送的数据写进去,这个代码写了有段时间了,过时了别找我。

dll文件代码:

#include <windows.h>
#include <winsock.h>

#include "process.h"


#include "stdio.h"
#pragma comment(lib,"ws2_32.lib")



typedef int (WINAPI *PFNMESSAGEBOX)(SOCKET s, const char FAR* buf, int len, int flags);
int WINAPI sendProxy(SOCKET s, const char FAR* buf, int len, int flags);
int * addr = (int *)GetProcAddress(GetModuleHandle("ws2_32"),"send");        //保存函数的入口地址
int * myaddr = (int *)sendProxy;
char ip[20]="";

DWORD WINAPI PROSOCK(LPVOID lpwoid);
DWORD WINAPI PROSOCK1(LPVOID lpwoid);

bool change=0;

bool AfxHookCode(void* TargetProc, void* NewProc,void ** l_OldProc, int bytescopy = 5)
{

  DWORD dwOldProtect;

  ::VirtualProtect((LPVOID)TargetProc, bytescopy, PAGE_EXECUTE_READWRITE, &dwOldProtect);

  *l_OldProc = new unsigned char[bytescopy+5];          // 为拷贝执行被覆盖的指令申请空间


  memcpy(*l_OldProc, TargetProc, bytescopy);           // 事先保存被破坏的指令

  *((unsigned char*)(*l_OldProc) + bytescopy) = 0xe9;    // 我的内存的代码执行完 跳到原来的 代码 + 破坏的代码的长度 上去

                            //被破坏指令的长度     //E9 opcode长度          //算出偏移的OPCODE    = 被HOOK函数地址的地址 + 破坏指令的长度 - 我分配内存的结束地址                           
    *(unsigned int *)((unsigned char*)(*l_OldProc) +bytescopy          +     1)          =   (unsigned int)(TargetProc) + bytescopy - ( (unsigned int)((*l_OldProc)) + 5 + bytescopy ) ;  // 我内存代码跳到原来代码上的偏移


  *(unsigned char*)TargetProc =(unsigned char)0xe9;             //被HOOK的函数头改为jmp


                                  //算出偏移的OPCODE  = 代理函数地址 - 被HOOK函数地址
  *(unsigned int*)((unsigned int)TargetProc +1) = (unsigned int)NewProc - ( (unsigned int)TargetProc + 5) ; //被HOOK的地方跳到我的新过程 接受过滤


  ::VirtualProtect((LPVOID)TargetProc, bytescopy, dwOldProtect, 0);
  change=1;
  return true;
}


bool AfxUnHookCode(void* TargetAddress, void * l_SavedCode, unsigned int len)
{
    DWORD dwOldProtect;

    ::VirtualProtect((LPVOID)TargetAddress, len, PAGE_EXECUTE_READWRITE, &dwOldProtect);  

    // 恢复被破坏处的指令
    memcpy(TargetAddress, l_SavedCode, len);

    ::VirtualProtect((LPVOID)TargetAddress, len, dwOldProtect, 0);
 change=0;

    return true;
}

unsigned int *  OldProc;
CRITICAL_SECTION g_cs;





  BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
  {

            switch ( fdwReason )
       {
      case DLL_PROCESS_ATTACH:
           {     

MessageBox( NULL, "注入目标进程", "信息", MB_ICONINFORMATION );
      CreateThread(0,0,PROSOCK,0,0,0); 

              
           }
          break;
      case DLL_PROCESS_DETACH:
           {
               MessageBox( NULL, "脱离目标进程", "信息", MB_ICONINFORMATION );
           }
          break;
       }
      return TRUE;
  }

DWORD WINAPI PROSOCK(LPVOID lpwoid)

InitializeCriticalSection(&g_cs); 
WSAData wsaData;
 WSAStartup(MAKEWORD(2,2),&wsaData);
  AfxHookCode((void*)addr, (void*)myaddr, (void**)&OldProc, 5);
MessageBox( NULL, "修改完", "信息", MB_ICONINFORMATION );


 return 0;
}

DWORD WINAPI PROSOCK1(LPVOID lpwoid)


EnterCriticalSection(&g_cs);
if(change==0)
{
 AfxHookCode((void*)addr, (void*)myaddr, (void**)&OldProc, 5);
}

LeaveCriticalSection(&g_cs); 
return 0;
}


int WINAPI sendProxy(SOCKET s, const char FAR* buf, int len, int flags)
{EnterCriticalSection(&g_cs);

sockaddr_in addrMy;
 memset(&addrMy,0,sizeof(addrMy));
 int leng = sizeof(addrMy);

int ret = getpeername(s,(sockaddr*)&addrMy,&leng);
 if (ret != 0)
 {
  MessageBox( NULL,"获取IP失败", "信息", MB_ICONINFORMATION );
  return 0;
 }
// char port[10]="";
//  itoa(ntohs(addrMy.sin_port),port,10);
strcpy(ip,inet_ntoa(addrMy.sin_addr));
FILE *fp=fopen("D:\\a.txt","w+");
if(fp){
fseek(fp,0,2);
fwrite(ip,sizeof(ip),1,fp);
fwrite(buf,len,1,fp);
fwrite(" ",sizeof(" "),1,fp);
fclose(fp);
}
else MessageBox(NULL,"ERROR","",MB_OK);
AfxUnHookCode((void*)addr, OldProc, 5);  
CreateThread(0,0,PROSOCK1,0,0,0);
LeaveCriticalSection(&g_cs);
        return    ((PFNMESSAGEBOX)addr)(s, buf, len, flags);
        //这个地方可以写出对这个API函数的处理代码
}

注入器代码:

  #include<stdio.h>
  #include<windows.h>
  #include<tlhelp32.h>
  #include<iostream>
  #include<tchar.h>
  using namespace std;
  char Data[MAX_PATH]="";
  bool WriteMemory(const HANDLE hProcess,const DWORD dwSize,const LPVOID lpRemoteBuf,const LPVOID Data)
  {
    DWORD dwNumberOfBytesWritten;
    if(lpRemoteBuf==NULL)//lpRemoteBuf表示一个指向目标进程地址空间的缓冲区
    {
      return false;//如果lpRemoteBuf等于NULL表示在目标进程地址空间申请内存失败了
    }
    if(WriteProcessMemory(hProcess,lpRemoteBuf,Data,dwSize,&dwNumberOfBytesWritten))//如果申请内存没有失败则想目标进程的缓冲区写入数据
    {
      if(dwSize!=dwNumberOfBytesWritten)//dwSize是要写入的数据大小,dwNumberOfBytesWritten是实际写入的数据大小
      {
                          //如果dwSize不等于dwNumberOfBytesWritten则表示输入写入不完整,同样以失败告终
        VirtualFreeEx(hProcess,lpRemoteBuf,dwSize,MEM_DECOMMIT);
        CloseHandle(hProcess);
        return false;
      }
    }
    else
    {
      CloseHandle(hProcess);
      return false;
    }
    return true;
  }


bool ProcessInjection(const unsigned int ProcessID)
  {
          //OpenProcess第一个参数指定要对该进程进行的操作(也就是权限)
          //PROCESS_CREATE_THREAD表示可以在目标进程中创建远程线程,也就是使用CreateRemoteThread的权限;
          //PROCESS_VM_OPERATION表示可以在目标进程中分配/释放内存的权限,也就是使用 VirtualAllocEx/VirtualFreeEx的权限;
          //PROCESS_VM_WRITE表示可以向目标进程的地址空间写入数据,也就是使用 WriteProcessMemory的权限。
    HANDLE hProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,ProcessID);


    DWORD dwSize;
    dwSize=_tcslen(Data)+1;//计算要在目标进程中申请的内存大小
    LPVOID lpRemoteBuf=VirtualAllocEx(hProcess,NULL,dwSize,MEM_COMMIT,PAGE_READWRITE);//在目标进程中申请内存
         
          //这里就是调用上面我们刚才打造的写目标进程地址空间的函数,为了程序的结构不混乱所以把这部分单独封装成一个函数;
    if(!WriteMemory(hProcess,dwSize,lpRemoteBuf,(LPVOID)Data)) return false;
 
    DWORD dwRemoteThreadHandle;
          //这里有必要说明一写lpRemoteEntryFun是一个LPVOID指针,指向LoadLibraryA函数,但是我现在取的LoadLibraryA函数地址
          //是针对本进程而言的函数地址,对于目标进程而言LoadLibraryA的函数地址可能和我的不一样;
          //这个道理是对的,但是对于有些函数来说,也不完全正确,因为LoadLibraryA位于kernel32.dll之中;
          //而Win32下每个应用程序都会把kernel32.dll加载到进程地址空间中一个固定的地址中;
          //所以在这里LoadLibraryA函数地址在每个应用程序中的地址是一样的;
    LPVOID lpRemoteEntryFun=LoadLibraryA;
          //接下来就是创建一个远程线程,线程的入口函数是LoadLibraryA,参数就是我们已经写入目标进程地址空间的DLL名称
    HANDLE hRemoteThread=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)lpRemoteEntryFun,lpRemoteBuf,0,&dwRemoteThreadHandle);
 if (! hRemoteThread)  
 {  
  printf("远程线程创建失败:%d",GetLastError());  
  return 0;  
 }  
    WaitForSingleObject(hRemoteThread,INFINITE);//等待LoadLibraryA执行完毕
    CloseHandle(hRemoteThread);
    CloseHandle(hProcess);
    cout<<"DLL已经成功注入!"<<endl;
    return true;
  }
 void main()
  {
 GetCurrentDirectory(MAX_PATH,Data);
 strcat(Data,"\\sddll.dll");
 printf("%s",Data);
    unsigned int ProcessID;
    PROCESSENTRY32 stPE32;
    stPE32.dwSize=sizeof(stPE32);
    HANDLE hSnapshot=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    bool bMore=(bool)Process32First(hSnapshot,&stPE32);
    while(bMore)
    {
      cout<<stPE32.szExeFile<<" "<<stPE32.th32ProcessID<<endl;
      bMore=(bool)Process32Next(hSnapshot,&stPE32);
    }
          //在此我们可以选择一个要注入的进程ID
          cout<<"请输入要注入的进程ID:";
    cin>>ProcessID;
    ProcessInjection(ProcessID);
  }

我用VC6可以正常运行的

虚像:

评论 阅读