最近在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。谁有时间研究一下可行性。