标签:creat class 获取 mcr 方法 thread eem cal dia
jmp ShellCodeStart Addr_IAT_LoadLibraryA dd 402000h ;LoadLibraryA在IAT中的地址,由注入函数写入 Addr_LoadLibraryA dd 7C801D77h ;LoadLibraryA的地址,由注入函数写入,在ShellCode + 2 + 4处 Addr_VirtualProtectName db "VirtualProtect",0 ;VirtualProtect名称的地址 Addr_LoadDllName db "InputDll.dll",0 ShellCodeStart: push ebx push ecx push edx push esi push edi push ebp xor ecx, ecx ;查找kernel32.dll基址放入eax,xor ecx, ecx不可丢 assume fs:nothing mov esi, fs:[30h] ;取PEB mov esi, [esi+0Ch] mov esi, [esi+1Ch] InInitializationOrderModuleList: mov eax, ds:[esi+8] mov edi, ds:[esi+20h] mov esi, ds:[esi] cmp WORD ptr ds:[edi+18h],cx jnz InInitializationOrderModuleList push ebp call RelocLocation ;push eip,eip = 新RelocLocation的地址 RelocLocation: pop ebp ;将eip出栈给ebp,ebp = 新RelocLocation的地址 sub ebp, offset RelocLocation ;ebp = ebp - offset RelocLocation(原RelocLocation地址)= 新旧地址的差值(参考重定位),后续需重定位的地址 = 原地址 + ebp mov ecx, ebp ;取Addr_VirtualProtectName重定位后的地址并压栈 add ecx, offset Addr_VirtualProtectName invoke GetAPI, eax, ecx, 14 ;调用GetAPI获取VirtualProtect的地址 mov ebx, eax ;将获取的地址放入ebx中 mov eax, ebp ;取Addr_LoadDllName重定位后的地址并压栈 add eax, offset Addr_LoadDllName push eax lea esi, [ebp + Addr_LoadLibraryA] ;取Addr_LoadLibraryA重定位后的地址,并调用LoadLibraryA call DWORD ptr [esi] ;API为stdcall调用,自平衡堆栈 mov edi, [ebp + Addr_IAT_LoadLibraryA] ;取LoadLibraryA在IAT的地址 push eax ;随便压栈一个数,我们要用这个数的地址作为VirtualProtect的lpflOldProtect的地址,因为ShellCode的代码段不可写,只能用堆栈返回 push esp ;调用VirtualProtect修改IAT的写保护 push PAGE_READWRITE push 4 push edi call ebx pop eax mov eax, [esi] ;[esi] = LoadLibraryA的地址 mov [edi], eax ;将LoadLibraryA在IAT的地址改为IDHookLoadLibraryA的地址 pop ebp ;平衡 pop ebp pop edi pop esi pop edx pop ecx pop ebx jmp eax ;跳转至LoadLibraryA继续执行 GetAPI proc _Kernel32Base:DWORD, _szAPIName:DWORD, _APINameLength:DWORD local @SizeOfFNT:DWORD local @APIAddr:DWORD pushad mov ebx, _Kernel32Base assume ebx:ptr IMAGE_DOS_HEADER add ebx, [ebx].e_lfanew ;取PE的首地址,即PE标志位 assume ebx:ptr IMAGE_NT_HEADERS mov ebx, [ebx].OptionalHeader.DataDirectory.VirtualAddress add ebx, _Kernel32Base assume ebx:ptr IMAGE_EXPORT_DIRECTORY mov eax, [ebx].NumberOfNames ;将函数总数乘以4,得FNT表大小 shl eax, 2 mov @SizeOfFNT, eax mov edi, [ebx].AddressOfNames ;获取输出表API名称查询表(FNT)RVA add edi, _Kernel32Base ;获取输出表API名称查询表(FNT)内存地址 mov esi, _szAPIName mov ecx, _APINameLength xor edx, edx xor eax, eax ;eax置0 .while edx < @SizeOfFNT ;遍历Dll所有函数名称,当计数edx=Dll函数总数时退出循环 push ecx ;保存字符串长度 push edi ;保存edi,比较API名称 push esi mov edi, [edi] ;取API名称的RVA add edi, _Kernel32Base ;取API名称的内存地址 cld repe cmpsb pop esi ;将esi重新指向_szAPIName首地址 pop edi pop ecx jnz FAA_FindExportAPIAddr_NoFind ;如果ecx=0,说明函数字符全部相同 mov eax, [ebx].AddressOfFunctions ;取FAT表RVA add eax, _Kernel32Base ;取FAT表RVA内存地址 add eax, edx ;取查找函数FAT表项的地址 mov eax, [eax] ;取查找函数的RVA add eax, _Kernel32Base ;取查找函数的内存地址 mov @APIAddr, eax .break ;找到则退出循环 FAA_FindExportAPIAddr_NoFind: add edx, 4 ;计数+4指向下一个FNT表项 add edi, 4 ;edi指向下一个FNT表项 .endw assume ebx:nothing popad mov eax, @APIAddr ret
//名称:HookIAT
//功能:将要Hook的IAT地址换为我们shellcode的地址,并将原IAT地址替换为shellcode中要调用的地址
//参数1:_ProcessID= 加载进程的PID
//返回:成功则返回TURE,否则返回FALSE
BOOL HookIAT(IN HANDLE _ProcessID,  IN PUNICODE_STRING _FullImageName)
{
  PEPROCESS  pEProcess;
  PVOID      hModule, pHookAPIAddr;
  BOOL      HookIAT_Ret = FALSE;
  if (PsLookupProcessByProcessId(_ProcessID, &pEProcess) == STATUS_SUCCESS)
  {
    if (CheckProcessName(pEProcess->ImageFileName, HOOKPROCESSNAME) && (staHookFlag == FALSE))
    {
      KdPrint(("加载Dll=%wZ\n", _FullImageName));
      //KdPrint(("_ProcessID=%x\n", (ULONG)_ProcessID));
      //KdPrint(("pEProcess=%x\n", (ULONG)pEProcess));
      KdPrint(("进程名称=%s\n", pEProcess->ImageFileName));
      hModule = pEProcess->SectionBaseAddress;
      //KdPrint(("基地址=%x\n", (DWORD)hModule));
      KeAttachProcess(pEProcess);                            //切换至ring3空间
      
      pHookAPIAddr = FindIATAddr(hModule, HOOKDLLNAME, HOOKAPINAME);
      
      if (pHookAPIAddr)
      {
        if(InjectCode(pHookAPIAddr))
        {
          staHookFlag = TRUE;
          KdPrint(("ShellCode注入成功"));
          //UnInjectDll();
        }
        else
        {
          KdPrint(("ShellCode注入失败"));
        }
      } 
      else
      {
        KdPrint(("%s函数的IAT地址未找到\n", HOOKAPINAME));
      }
      
      KeDetachProcess();
    }
  }
  return HookIAT_Ret;
}
//名称:FindIATAddr
//功能:寻找指定导入表函数名称的IAT地址
//参数1:pMapView = 模块的映射基址
//参数2:pszDllName = Dll名称
//参数3:pszAPIName = 函数名称
//返回:成功则返回函数在导入表的地址,否则返回NULL
PVOID FindIATAddr(PVOID _pMapView, PCHAR  _pszDllName , PCHAR  _pszAPIName)
{
  DWORD  RVA_ImportDirectory;
  DWORD  DllNum, i, index;
  PVOID    pDllName;
  PWORD    pIAT, pINT;
  PIMAGE_IMPORT_BY_NAME pAPIName;
  IMAGE_DOS_HEADER *pImg_DosHeader;
  IMAGE_NT_HEADERS *pImg_NtHeader;
  PIMAGE_IMPORT_DESCRIPTOR pImg_ImportDirectory;
  
  pImg_DosHeader = _pMapView;
  (ULONG)pImg_NtHeader = (ULONG)pImg_DosHeader + pImg_DosHeader->e_lfanew;
  if (pImg_NtHeader->Signature != 0x4550)                    //判断是否为标准PE文件          
  {
    KdPrint(("该文件不是标准PE文件\n"));
    return  NULL;    
  }  
  
  RVA_ImportDirectory = pImg_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  DllNum = pImg_NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) ;
  DllNum --;
  if (RVA_ImportDirectory ==0)
  {
    KdPrint(("该程序没有输入表\n"));
    return  NULL;
  }
  KdPrint(("Dll数目=%d \n", DllNum));
  (DWORD)pImg_ImportDirectory = (DWORD)_pMapView + RVA_ImportDirectory;
  for (i=0; i<DllNum ; i++)
  {
    (DWORD)pDllName = pImg_ImportDirectory[i].Name + (DWORD)_pMapView;
    //KdPrint(("Dll名称为%s: \n", pDllName));
    if(VK_CmpString(pDllName, _pszDllName))
    {
      KdPrint(("%s已找到, i=%d  \n", pDllName, i));
      (DWORD)pImg_ImportDirectory += i*sizeof(IMAGE_IMPORT_DESCRIPTOR);
      (DWORD)pIAT = (DWORD)_pMapView + pImg_ImportDirectory->FirstThunk;
      (DWORD)pINT =  (DWORD)_pMapView + pImg_ImportDirectory->OriginalFirstThunk;
      for (index =0; pIAT[index] != 0; index++)
      {
        if ((pINT[index] & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)          //IMAGE_ORDINAL_FLAG =0x80000000,即当INT最高位为0时表示已函数名导入
        {
          (DWORD)pAPIName = (DWORD)_pMapView + pINT[index];
          //KdPrint(("API名称为%s: \n", pAPIName->Name));
          if (VK_CmpString((PCHAR)pAPIName->Name, _pszAPIName))
          {
            KdPrint(("%s函数已找到,IAT地址 =%x \n", pAPIName, &pIAT[index] ));
            return  &pIAT[index];
          }
        }
      }
    }
  }
  return NULL;
}
//名称:InjectCode
//功能:注入代码
//参数1:_pIATAddr = 函数在导入表的地址,将此处改写为我们注入代码的地址
//返回:成功则返回STATUS_SUCCESS,否则返回STATUS_UNSUCCESSFUL
BOOL InjectCode(PVOID _pIATAddr)
{
  PMDL  pMDL;
  PDWORD pHookAddr;
  DWORD Addr_sharedM = 0x7ffe0800;        //KUSER_SHARED_DATA在ring3的地址 + ShellCode的偏移    
  DWORD Addr_sharedK = 0xffdf0800;         //KUSER_SHARED_DATA在ring0的地址 + ShellCode的偏移
  unsigned char Shellcode[] = {
    0xEB,0x24,0x00,0x20,0x40,0x00,0x77,0x1D,0x80,0x7C,0x56,0x69,0x72,0x74,0x75,0x61,0x6C,0x50,0x72,0x6F,0x74,0x65,0x63,0x74,0x00,0x49,0x6E,0x70,0x75,0x74,0x44,0x6C
    ,0x6C,0x2E,0x64,0x6C,0x6C,0x00,0x53,0x51,0x52,0x56,0x57,0x55,0x33,0xC9,0x64,0x8B,0x35,0x30,0x00,0x00,0x00,0x8B,0x76,0x0C,0x8B,0x76,0x1C,0x8B,0x46,0x08,0x8B,0x7E
    ,0x20,0x8B,0x36,0x66,0x39,0x4F,0x18,0x75,0xF2,0x55,0xE8,0x00,0x00,0x00,0x00,0x5D,0x81,0xED,0x65,0x10,0x40,0x00,0x8B,0xCD,0x81,0xC1,0x20,0x10,0x40,0x00,0x6A,0x0E
    ,0x51,0x50,0xE8,0x2F,0x00,0x00,0x00,0x8B,0xD8,0x8B,0xC5,0x05,0x2F,0x10,0x40,0x00,0x50,0x8D,0xB5,0x1C,0x10,0x40,0x00,0xFF,0x16,0x8B,0xBD,0x18,0x10,0x40,0x00,0x50
    ,0x54,0x6A,0x04,0x6A,0x04,0x57,0xFF,0xD3,0x58,0x8B,0x06,0x89,0x07,0x5D,0x5D,0x5F,0x5E,0x5A,0x59,0x5B,0xFF,0xE0,0x55,0x8B,0xEC,0x83,0xC4,0xF8,0x60,0x8B,0x5D,0x08
    ,0x03,0x5B,0x3C,0x8B,0x5B,0x78,0x03,0x5D,0x08,0x8B,0x43,0x18,0xC1,0xE0,0x02,0x89,0x45,0xFC,0x8B,0x7B,0x20,0x03,0x7D,0x08,0x8B,0x75,0x0C,0x8B,0x4D,0x10,0x33,0xD2
    ,0x33,0xC0,0xEB,0x28,0x51,0x57,0x56,0x8B,0x3F,0x03,0x7D,0x08,0xFC,0xF3,0xA6,0x5E,0x5F,0x59,0x75,0x12,0x8B,0x43,0x1C,0x03,0x45,0x08,0x03,0xC2,0x8B,0x00,0x03,0x45
    ,0x08,0x89,0x45,0xF8,0xEB,0x0B,0x83,0xC2,0x04,0x83,0xC7,0x04,0x3B,0x55,0xFC,0x72,0xD3,0x61,0x8B,0x45,0xF8,0xC9,0xC2,0x0C,0x00 }; 
  
  KdPrint(("_pIATAddr = %x\n",  (DWORD)_pIATAddr ));
  pMDL = MmCreateMdl(NULL, _pIATAddr, 4);
  if (!pMDL)
  {
    KdPrint(("创建MDL失败\n"));
    return  FALSE;
  }
  MmBuildMdlForNonPagedPool(pMDL);
  pMDL->MdlFlags = pMDL->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
  pHookAddr = MmMapLockedPages(pMDL, KernelMode);
  //_asm int 3
  RtlCopyMemory((PVOID)Addr_sharedK, Shellcode, 249);
  _asm                                                         //将LoadLibraryA输出表地址地址和LoadLibraryA地址写入ShellCode中
  {
    pushad
    
    mov    eax, _pIATAddr
    mov    edx, Addr_sharedK
    add    edx, 2
    mov    [edx], eax
    mov    eax, [eax]
    add    edx, 4
    mov    [edx], eax
    popad
  }
  //RtlCopyMemory((PVOID)(Addr_sharedK +5), _pIATAddr, 4);                    
  *pHookAddr = Addr_sharedM;                                    //将LoadLibraryA输出表地址改为0x7ffe0800(ShellCode地址)
  
  MmUnmapLockedPages(pHookAddr, pMDL);
  IoFreeMdl(pMDL);
  return  TRUE;
}
//名称:UnInjectDll
//功能:PsSetLoadImageNotifyRoutine的回调函数,
//参数1:无
//返回:无
NTSTATUS UnInjectDll()
{
  NTSTATUS  RetStatus;
  RetStatus = PsRemoveLoadImageNotifyRoutine(CallImageNotifyRoutines);
  if (RetStatus == STATUS_SUCCESS)
  {
    KdPrint(("回调函数已解除\n"));
  }
  return  RetStatus;
}
 
                        
			
                          
			标签:creat class 获取 mcr 方法 thread eem cal dia
原文地址:http://www.cnblogs.com/kuangke/p/6259366.html