看流星社区

 找回密码
 注册账号
查看: 1993|回复: 0

Win7下的GetProcAddress

[复制链接]

该用户从未签到

发表于 2013-4-18 09:06:52 | 显示全部楼层 |阅读模式
最近在WIN7下跑原来写的一个壳。发现自己写的GetProcAddress出错。分析了ntdll里的LdrGetProcedureAddress函数。查了一些资料发现。Win7引入了ApiSetMap的机制。它把一些系统低级别的一些API分为几个类型并且把kernel32.dll与advapi32.dll的一部分函数放到kernelbase.dll里。而归类的API名由api-ms-xxx字符串的dll库引入。这些DLL在系统上并不存在而只是一个索引类似的东西存在于引出表中。起一个重定向的问题。
在每一个进程的PEB+0x38偏移处就是ApiSetMap字段了。翻阅了一些文档,这个东西是存在于ApiSetMap.dll中的.apimap节中而此节是在WIN7启动时在启动1阶段被加载到系统空间,而0x38是这个的用户空间映射(这些我没有去验证,有时间的朋友可以自行去验证一下)。这个结构是这样的。

代码:
// ApiSetMap结构
typedef struct _API_SET_MAP_HEADER {
__dword dwVersionNumber;
__dword dwNumberOfApiSetModules;
} API_SET_MAP_HEADER, *PAPI_SET_MAP_HEADER;

typedef struct _API_SET_MAP_ENTRY {
__dword dwNameOfApiSetModuleRVA;
__dword dwSizeOfName;
__dword dwHostModulesRVA;
} API_SET_MAP_ENTRY, *PAPI_SET_MAP_ENTRY;

typedef struct _API_SET_MAP_HOST_HEADER {
__dword dwNumberOfHosts;
} API_SET_MAP_HOST_HEADER, *PAPI_SET_MAP_HOST_HEADER;

typedef struct _API_SET_MAP_HOST_ENTRY {
__dword dwNameOfImportModuleRVA;
__dword dwSizeOfImportModuleName;
__dword dwNameOfHostRVA;
__dword dwSizeOfHostName;
} API_SET_MAP_HOST_ENTRY, *PAPI_SET_MAP_HOST_ENTRY;
由两个头 两个Entry组成。只有一个ApiSetMapHeader,紧随其后的是ApiSetMapHeader.dwNumberOfApiSetModules个ApiSetMapEntry而在此结构ApiSetMapEntry.dwHostModulesRVA又是ApiSetMapHostHeader结构的相对于ApiSetMapHeader的偏移。而在ApiSetMapHostHeader下又有ApiSetMapHostHeader.dwNumberOfHosts个ApiSetMapHostEntry结构,在这个结构中存在着一些对应。现在发现最多是2个HostEntry结构,最少是1个。

而我们要找的就是ImportMoude的名字与我们原先加载DLL的名字一样下面的HostModule的名字。大多数都是kernel32.dll -> kernelbase.dll的映射。
如果只有1个HostEntry那么ImportModule名为空。而HostModule为kernel32.dll,这个应该是为advapi32.dll准备的。advapi32.dll的一部分函数被重定向到kernel32.dll里了。

我语言组织的不太好。下面直接给出代码,一看就明白了。


代码:
// 获取ApiSetMap
PAPI_SET_MAP_HEADER __API__ GetApiSetMapHeader() {
PAPI_SET_MAP_HEADER pApiSetMap = NULL;
__memory pPeb = NULL;
// 检查是否是Vista以上系统
if (GetWindowsVersion() != WIN_VISTA)
  return NULL;
pPeb = (__memory)__NtCurrentPeb__();
pApiSetMap = (PAPI_SET_MAP_HEADER)*((__address *)(pPeb + 0x38));
return pApiSetMap;
}

// 私有函数这里声明一下,底下函数有要用
FARPROC __INTERNAL_FUNC__ xLdrGetExportByName(__memory pBaseAddress, __memory pHashPoint, __integer iHashSize, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA);
FARPROC __INTERNAL_FUNC__ xLdrGetExportByOrdinal(__memory pBaseAddress, __word wOrdinal, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA);
__INLINE__ FARPROC __INTERNAL_FUNC__ xLdrFixupForward(__memory pBaseAddress, __memory pForwardName, __word wOrdinal, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA) {
__char NameBuffer[128] = {0};
__wchar NameOfLib[128] = {0};
__memory pPoint = NULL;
__memory hModule = NULL;
__byte HashValue[1024] = {0};
__integer iHashValueSize = 0;
FARPROC pFunction = NULL;
// 获取加载动态库的地址
FPLoadLibraryA pLoadLibraryA = (FPLoadLibraryA)fpLoadLibraryA;
// 取出DLL与引出的函数名
__logic_strcpy__(NameBuffer, pForwardName);
pPoint = __logic_strchr__(NameBuffer, '.');
if (pPoint) {
  __char *pProcName = NULL;
  __integer iProcNameSize = 0;
  *pPoint = 0;//使用0字符将DLL与函数名隔开,替代'.'
  // 检查是否是ApiSetMap的函数
  __logic_str2lower__(NameBuffer);//转换为小写
  if (__logic_strncmp__(NameBuffer, "api-", 4) == 0) {
   // 寻找API SET MAP
   PAPI_SET_MAP_HEADER pApiSetMapHeader = NULL;
   PAPI_SET_MAP_ENTRY pApiSetMapEntry = NULL;
   __dword dwNumberOfApiSetMapEntry = 0;
   __dword dwNumberOfHostEntry = 0;
   __wchar *pApiSetMapEntryName = NULL;
   __integer iSizeOfApiSetMapEntryName = 0;
   __wchar *pHostMapName = NULL;
   __integer iSizeOfHostMapName = 0;
   __wchar *pImportMapName = NULL;
   __integer iSizeOfImportMapName = 0;
   PAPI_SET_MAP_HOST_HEADER pApiSetMapHostHeader = NULL;
   PAPI_SET_MAP_HOST_ENTRY pApiSetMapHostEntry = NULL;
   __integer i = 0, j = 0;
   __char *pNameBuffer = NULL;
   // 获取要匹配的库名
   pNameBuffer = (__char *)(NameBuffer + 4);
   pApiSetMapHeader = GetApiSetMapHeader();
   if (!pApiSetMapHeader) return NULL;
   pApiSetMapEntry = (PAPI_SET_MAP_ENTRY)((__memory)pApiSetMapHeader + sizeof(API_SET_MAP_HEADER));
   dwNumberOfApiSetMapEntry = pApiSetMapHeader->dwNumberOfApiSetModules;
   for (i = 0; i < dwNumberOfApiSetMapEntry; i++, pApiSetMapEntry++) {
    __char AnsiNameOfLib[128] = {0};
    pApiSetMapEntryName = (__wchar *)((__memory)pApiSetMapHeader + pApiSetMapEntry->dwNameOfApiSetModuleRVA);
    iSizeOfApiSetMapEntryName = pApiSetMapEntry->dwSizeOfName;
    // 转换成小写
    __logic_memset__(NameOfLib, 0, sizeof(__wchar) * 128);
    __logic_memset__(AnsiNameOfLib, 0, 128);
    __logic_tcsncpy__(NameOfLib, pApiSetMapEntryName, iSizeOfApiSetMapEntryName);
    __logic_tcs2lower_n_(NameOfLib, iSizeOfApiSetMapEntryName / sizeof(__tchar));
    __logic_tcs2str_n__(NameOfLib, AnsiNameOfLib, iSizeOfApiSetMapEntryName / sizeof(__tchar));
    // 对比是否是要查找的Lib
    if (__logic_strcmp__(AnsiNameOfLib, pNameBuffer) == 0) {
     __integer iCount = 0;
     PLDR_MODULE pLdrImportModule = NULL;
     __char szImportModuleName[128] = {0};
     PUNICODE_STRING pCurrImportName = NULL;
     pApiSetMapHostHeader = (PAPI_SET_MAP_HOST_HEADER)((__memory)pApiSetMapHeader + pApiSetMapEntry->dwHostModulesRVA);
     dwNumberOfHostEntry = pApiSetMapHostHeader->dwNumberOfHosts;
     pApiSetMapHostEntry = (PAPI_SET_MAP_HOST_ENTRY)((__memory)pApiSetMapHostHeader + sizeof(API_SET_MAP_HOST_HEADER));
     // 找到当前模块的引入模块
     pLdrImportModule = GetExistModuleInLoadModuleList(pBaseAddress);
     pCurrImportName = &(pLdrImportModule->BaseDllName);
     
     // 如果dwNumberOfHostEntry == 1
     if (dwNumberOfHostEntry == 1) {
      // Host
      pHostMapName = (__wchar *)((__memory)pApiSetMapHeader + pApiSetMapHostEntry->dwNameOfHostRVA);
      iSizeOfHostMapName = pApiSetMapHostEntry->dwSizeOfHostName;
      iCount = iSizeOfHostMapName / sizeof(__tchar);
      // 转换
      __logic_tcs2str_n__(pHostMapName, NameBuffer, iCount);
      NameBuffer[iCount] = '\0';
      // 跳转到
      goto _load_library_get_address;
     } else {
      // 遍历Host映射
      for (j = 0; j < dwNumberOfHostEntry; j++, pApiSetMapHostEntry++) {
       __wchar ImportModule[128] = {0};
       __wchar ImportModule2[128] = {0};
       // Import
       pImportMapName = (__wchar *)((__memory)pApiSetMapHeader + pApiSetMapHostEntry->dwNameOfImportModuleRVA);
       iSizeOfImportMapName = pApiSetMapHostEntry->dwSizeOfImportModuleName;
       iCount = iSizeOfImportMapName / sizeof(__tchar);
       // 如果引入模块名长度为0
       if (iSizeOfImportMapName == 0)
        continue;
       // Host
       pHostMapName = (__wchar *)((__memory)pApiSetMapHeader + pApiSetMapHostEntry->dwNameOfHostRVA);
       iSizeOfHostMapName = pApiSetMapHostEntry->dwSizeOfHostName;
       __logic_tcsncpy__(ImportModule, pImportMapName, iCount);
       __logic_tcs2lower_n_(ImportModule, iCount);
       ImportModule[iCount] = _T('\0');
       __logic_tcsncpy__(ImportModule2, pCurrImportName->Buffer, iCount);
       __logic_tcs2lower_n_(ImportModule2, iCount);
       ImportModule2[iCount] = _T('\0');
       // 比对Import模块的名字, 如果相等则获取
       if (__logic_tcsncmp__(pImportMapName, ImportModule2, iCount) == 0) {
        iCount = iSizeOfHostMapName / sizeof(__tchar);
        __logic_tcs2str_n__(pHostMapName, NameBuffer, iCount);
        NameBuffer[iCount] = '\0';
        goto _load_library_get_address;
       }/* end if */
      }/* end for */
     }/* end else */
    }/* end if */
   }/* end for */
  } else {
_load_library_get_address:
   // 加载动态库
   hModule = (__memory)pLoadLibraryA(NameBuffer);
   if (!hModule) return NULL;
   // 产生哈希值
   pProcName = (__char *)(pPoint + 1);
   iProcNameSize = __logic_strlen__(pPoint + 1);
   iHashValueSize = pHashFunc((__memory)pProcName, iProcNameSize, HashValue);
   return xLdrGetExportByName((__memory)hModule, (__memory)HashValue, iHashValueSize, pHashFunc, fpLoadLibraryA);
  }/* end else */
}/* end if */
return NULL;
}
FARPROC __INTERNAL_FUNC__ xLdrGetExportByOrdinal(__memory pBaseAddress, __word wOrdinal, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA) {
PIMAGE_EXPORT_DIRECTORY pExportDir;
__integer iExportDirSize;
__dword **pExFunctionsPoint;
FARPROC pFunction;
PIMAGE_DATA_DIRECTORY pExportDataDirectory = ExistDataDirectory(pBaseAddress, IMAGE_DIRECTORY_ENTRY_EXPORT);
pExportDir = (PIMAGE_EXPORT_DIRECTORY)(pBaseAddress + pExportDataDirectory->VirtualAddress);
if (!pExportDir)
  return NULL;
iExportDirSize = pExportDataDirectory->Size;
pExFunctionsPoint = (__dword **)__RvaToVa__(pBaseAddress, pExportDir->AddressOfFunctions);
pFunction = (FARPROC)(0 != pExFunctionsPoint[wOrdinal - pExportDir->Base]
    ? __RvaToVa__(pBaseAddress, pExFunctionsPoint[wOrdinal - pExportDir->Base])
    : NULL);
if (((__address)pFunction >= (__address)pExportDir) &&
  ((__address)pFunction < (__address)pExportDir + (__address)iExportDirSize))
  pFunction = xLdrFixupForward(pBaseAddress, (__memory)pFunction, wOrdinal, pHashFunc, fpLoadLibraryA);
return pFunction;
}
FARPROC __INTERNAL_FUNC__ xLdrGetExportByName(__memory pBaseAddress, __memory pHashPoint, __integer iHashSize, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA) {
__word wOrdinal = 0;
__integer iDirCount = 0;
__address *pAddrTable = NULL;
__address addrAddr = 0;
__offset ofRVA = 0;
__integer iExpDataSize = 0;
__integer i = 0;
PIMAGE_EXPORT_DIRECTORY pEd = NULL;
PIMAGE_NT_HEADERS pNt = NULL;
PIMAGE_DATA_DIRECTORY pExportDataDirectory = NULL;
if (pBaseAddress == NULL) return NULL;
pNt = GetNtHeader(pBaseAddress);
iDirCount = pNt->OptionalHeader.NumberOfRvaAndSizes;
if (iDirCount < IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return FALSE;
pExportDataDirectory = ExistDataDirectory(pBaseAddress, IMAGE_DIRECTORY_ENTRY_EXPORT);
if(!pExportDataDirectory)
  return NULL;//确定引出表
iExpDataSize = pExportDataDirectory->Size;
// 从引出表获取函数地址
pEd = (PIMAGE_EXPORT_DIRECTORY)__RvaToVa__(pBaseAddress, pExportDataDirectory->VirtualAddress);
/*
* 获取序数引出的函数
*/
if (HIWORD((__dword)pHashPoint)==0) {//以序号引出
  wOrdinal = (__word)(LOWORD((__dword)pHashPoint)) - pEd->Base;
} else {
  __integer iCount = 0;
  __dword *pdwNamePtr = NULL;
  __word *pwOrdinalPtr = NULL;
  iCount = (__integer)(pEd->NumberOfNames);
  pdwNamePtr = (__dword *)__RvaToVa__(pBaseAddress, pEd->AddressOfNames);
  pwOrdinalPtr = (__word *)__RvaToVa__(pBaseAddress, pEd->AddressOfNameOrdinals);
  for(i = 0; i < iCount; i++) {
   __byte HashValue[1024];
   __char *svName = NULL;
   __integer iHashValueSize = 0;
   svName = (__char *)__RvaToVa__(pBaseAddress, *pdwNamePtr);
   iHashValueSize = pHashFunc(svName, __logic_strlen__(svName), HashValue);//进行哈希计算
   if (iHashValueSize == iHashSize) {
    if (__logic_memcmp__(HashValue, pHashPoint, iHashSize) == 0) {
     wOrdinal = *pwOrdinalPtr;
     break;
    }
   }
   pdwNamePtr++;
   pwOrdinalPtr++;
  }
  if (i == iCount) return NULL;
}
pAddrTable=(__address *)__RvaToVa__(pBaseAddress, pEd->AddressOfFunctions);
ofRVA = pAddrTable[wOrdinal];
addrAddr = (__address)__RvaToVa__(pBaseAddress, ofRVA);
/*
  * 最终判断是否是中间跳转
  */
if (((__address)addrAddr >= (__address)pEd) &&
  ((__address)addrAddr < (__address)pEd + (__address)iExpDataSize))
  return xLdrFixupForward(pBaseAddress, (__memory)addrAddr, wOrdinal, pHashFunc, fpLoadLibraryA);
return (FARPROC)addrAddr;
}
__INLINE__ FARPROC __INTERNAL_FUNC__ xLdrGetProcedureAddress(__memory pBaseAddress, __memory pHashPoint, __integer iHashSize, FPHashFunc pHashFunc, FARPROC fpLoadLibraryA) {
FARPROC pProcedureAddress = NULL;
__dword dwOrdinal = (__dword)pHashPoint;
if (HIWORD((__dword)pHashPoint)) {
  // 通过名字引出
  pProcedureAddress = xLdrGetExportByName(pBaseAddress, pHashPoint, iHashSize, pHashFunc, fpLoadLibraryA);
} else {
  // 通过序数
  dwOrdinal &= 0x0000FFFF;
  pProcedureAddress = xLdrGetExportByOrdinal(pBaseAddress, (__word)dwOrdinal, pHashFunc, fpLoadLibraryA);
}
return pProcedureAddress;
}

我逆向的是win7下ntdll中的位于0x77F1E681 -> 0x77F1E6F1 -> 0x77F22193 这三个函数就是主要ntdll实现对ApiSetMap的解析了。

一个邪恶的想法是是否可以在内核里直接劫持这片空间。把他们的映射关系修改我们自己的DLL。谁有时间研究一下可行性。
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-30 12:58

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表