API Hook

ApiHook又叫做API劫持,也就是如果A程序调用了B.cll里面的C函数,我们可以做到当A调用C函数执行的时候,直接执行我们自己事先准备好的函数,之后我们在执行真正的C,当然我们可以不执行C或者更改C的参数等等,实现的核心思路就是:

mov eax, pNewAddr[/size][size=3] jmp eax

解释下具体原理:我们首先获取要劫持函数的地址,然后我们在自己组装一个数据结构,数据结构的内容是 执行汇编:把新函数地址拷到寄存器里,然后再jmp到新函数地址位置执行新函数,然后我们把自己组装这个数据结构拷贝到之前获取的需要劫持的函数地址指向的内存的位置,这样当我们再次调用该函数的时候,程序走到函数地址处发现是执行我们刚刚写好的汇编命令,直接jmp到了我们自己定义的函数地址的位置,也就相当于直接运行了我们自己写好的函数地址了,当然自己写的函数必须要和原函数参数和返回值一样,自己写的函数里面也可以调用原函数(达到过滤的目的),但是前提是调用之前要先关闭劫持,也就是把我们替换的内容给人家替换回去,执行完之后再次替换我们的地址,如果不替换回去我们就会进入无限递归了这个不解释,当然我们也可以修改参数什么的,给调用者进行一个“加工”。还有就是刚开始看的时候有一个地方不理解就是:DLL注入能成功的原理是,某些系统DLL里面的函数所有程序调用都会执行同一个地址,而APIHook中有一步是更改函数地址,但是如果我们更改了某些公用的函数地址,那么并不会影响其他的程序继续调用,这个地方小纠结了一会,后来弄清楚了,A加载了系统B.DLL获取里面的API函数C,
A2也同样加载并且获取了里面的API函数C2,C和C2是相等的(当然并不是所有都相等),但是我们在A程序里进行C函数的Hook,并没有影响A2的调用,原因是他们只是指向同一个地址不是就是同一个地址,可以理解成是中间有过度变量。我们修改的只是自己内存那部分”本分而已”,这样的话,我们想要Hook某个继承的某些API的话通常可以采取DLL注入的方式,DLL注入之前我总结过并且上传过相关的实现代码。这里不解释。然后就是在网上找到了一个写的不错的APIHook的代码,分享下(注意,下面代码是方便理解的,可以通过代码好好理解,但是实际开发不要用下面的代码,因为下面没考虑64位等其他问题,我平时开发常用的一个比较稳定的代码我上传在:http://download.csdn.net/detail/u013761036/9603063):

AdHookApi.h
#ifndef __ADHOOKAPI_H__
#define __ADHOOKAPI_H__
#include <windows.h>
#include <tchar.h>
#include <vector>
using namespace std; // class CAdAutoHookApi
class CAdHookApi;
class CAdAutoHookApi
{
public:
CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr);
virtual ~CAdAutoHookApi(); private:
CAdHookApi *m_pHookApi;
void *m_pAddr;
}; // class CAdAutoHook
class CAdHookApi
{
public:
CAdHookApi();
virtual ~CAdHookApi(); protected:
struct HookMap
{
HANDLE hProcess;
void *pOldAddr;
void *pNewAddr;
BYTE chOldCode[8];
BYTE chNewCode[8];
BOOL bHooked;
DWORD dwData;
};
public:
HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);
HANDLE Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData = NULL, DWORD verifySize = 0, DWORD dwData = 0);
BOOL Remove(HANDLE hHook);
BOOL Begin(HANDLE hHook);
BOOL End(HANDLE hHook);
BOOL Begin2(void *pNewAddr);
BOOL End2(void *pNewAddr);
int BeginAll();
int EndAll();
int GetCount();
void *OldAddr2NewAddr(void *pOldAddr);
void *NewAddr2OldAddr(void *pNewAddr); public:
static BOOL VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize); static BOOL PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode,
const BYTE *verifyData = NULL, DWORD verifySize = 0); protected:
CAdHookApi::HookMap *FromNewAddr(void *pNewAddr);
CAdHookApi::HookMap *FromOldAddr(void *pOldAddr);
BOOL HasHook(HANDLE hHook); protected:
vector<HookMap *> m_obHooks;
}; #endif // __ADHOOKAPI_H__ AdHookApi.cpp //#include "stdafx.h"
#include "AdHookApi.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
#include "Common.h" static BOOL gUseAPI = TRUE; static BOOL WINAPI myReadMemory(HANDLE hProcess, LPVOID lpAddress, LPVOID lpBuffer, SIZE_T nSize)
{
BOOL bRet = FALSE;
DWORD dwOldProtect = 0;
bRet = VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);
if(gUseAPI)
{
DWORD dwRead = 0;
bRet = ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);
}
else
{
memcpy(lpBuffer, lpAddress, nSize);
}
VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);
assert(bRet);
return bRet;
} static BOOL WINAPI myWriteMemory(HANDLE hProcess, LPVOID lpAddress, LPCVOID lpBuffer, SIZE_T nSize)
{
BOOL bRet = FALSE;
DWORD dwOldProtect = 0;
bRet = VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);
if(gUseAPI)
{
DWORD dwWrite = 0;
bRet = WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);
}
else
{
memcpy(lpAddress, lpBuffer, nSize);
}
VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);
assert(bRet);
return bRet;
} // class CAdAutoHookApi
CAdAutoHookApi::CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr)
{
m_pHookApi = pHookApi;
m_pAddr = pAddr; assert(m_pHookApi != NULL); if(m_pHookApi != NULL)
{
m_pHookApi->End2(m_pAddr);
}
} CAdAutoHookApi::~CAdAutoHookApi()
{
if(m_pHookApi != NULL)
{
m_pHookApi->Begin2(m_pAddr);
}
} // class CAdHookApi
CAdHookApi::CAdHookApi()
{
} CAdHookApi::~CAdHookApi()
{
EndAll();
} BOOL CAdHookApi::VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize)
{
BOOL isPassed = FALSE;
if((verifyData != NULL) && (verifySize > 0))
{
BYTE *addrData = new BYTE[verifySize];
if(myReadMemory(GetCurrentProcess(), pAddr, addrData, verifySize))
{
if(memcmp(addrData, verifyData, verifySize) == 0)
{
isPassed = TRUE;
}
}
delete []addrData;
}
else
{
isPassed = TRUE;
}
return isPassed;
} BOOL CAdHookApi::PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode,
const BYTE *verifyData, DWORD verifySize)
{
if(!VerifyAddress(pAddr, verifyData, verifySize))
{
return FALSE;
}
BOOL bRet = myWriteMemory(GetCurrentProcess(), pAddr, pCode, dwCode);
return bRet;
} HANDLE CAdHookApi::Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData)
{
HMODULE hModule = LoadLibrary(lpszModule);
if(hModule == NULL)
{
return NULL;
} void *pOldAddr = (void *)GetProcAddress(hModule, lpcFuncName);
if(pOldAddr == NULL)
{
return NULL;
} return Add(pOldAddr, pNewAddr, NULL, 0, dwData);
} HANDLE CAdHookApi::Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData, DWORD verifySize, DWORD dwData)
{
BOOL bRet = FALSE;
HookMap *pHook = new HookMap;
do
{
ZeroMemory(pHook, sizeof(HookMap)); pHook->hProcess = GetCurrentProcess(); pHook->pOldAddr = pOldAddr;
if(pHook->pOldAddr == NULL)
{
break ;
} DWORD dwRead = 8;
if((verifyData != NULL) && (verifySize > 0) && (verifySize > dwRead))
{
dwRead = verifySize;
}
BYTE *addrData = new BYTE[dwRead];
if(!myReadMemory(pHook->hProcess, pHook->pOldAddr, addrData, dwRead))
{
delete []addrData;
break ;
}
if((verifyData != NULL) && (verifySize > 0) && (memcmp(addrData, verifyData, verifySize) != 0))
{
delete []addrData;
break ;
}
memcpy(pHook->chOldCode, addrData, 8);
delete []addrData; DWORD dwTemp = (DWORD)pNewAddr;
pHook->pNewAddr = pNewAddr; // mov eax, pNewAddr
// jmp eax
pHook->chNewCode[0] = 0xB8;
memcpy(pHook->chNewCode + 1, &dwTemp, sizeof(DWORD));
pHook->chNewCode[5] = 0xFF;
pHook->chNewCode[6] = 0xE0; pHook->bHooked = FALSE; pHook->dwData = dwData; m_obHooks.push_back(pHook); bRet = TRUE;
}while(0);
if(!bRet)
{
delete pHook;
pHook = NULL;
} return (HANDLE)pHook;
} BOOL CAdHookApi::Remove(HANDLE hHook)
{
BOOL bRet = FALSE;
HookMap *pHook = (HookMap *)hHook;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
if(pTemp == pHook)
{
End((HANDLE)pTemp);
delete pHook;
m_obHooks.erase(m_obHooks.begin() + i);
bRet = TRUE;
break ;
}
} return bRet;
} BOOL CAdHookApi::Begin(HANDLE hHook)
{
if(!HasHook(hHook))
{
return FALSE;
}
HookMap *pHook = (HookMap *)hHook;
if(pHook->bHooked)
{
return TRUE;
}
DWORD dwWrite = 8;
BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chNewCode, dwWrite);
if(bRet)
{
pHook->bHooked = TRUE;
}
return bRet;
} BOOL CAdHookApi::End(HANDLE hHook)
{
if(!HasHook(hHook))
{
return FALSE;
}
HookMap *pHook = (HookMap *)hHook;
if(!pHook->bHooked)
{
return FALSE;
}
DWORD dwWrite = 8;
BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chOldCode, dwWrite);
if(bRet)
{
pHook->bHooked = FALSE;
}
return bRet;
} BOOL CAdHookApi::Begin2(void *pNewAddr)
{
HookMap *pHook = FromNewAddr(pNewAddr);
if(pHook == NULL)
{
return FALSE;
} return Begin((HANDLE)pHook);
} BOOL CAdHookApi::End2(void *pNewAddr)
{
HookMap *pHook = FromNewAddr(pNewAddr);
if(pHook == NULL)
{
return FALSE;
} return End((HANDLE)pHook);
} void *CAdHookApi::OldAddr2NewAddr(void *pOldAddr)
{
HookMap *pHook = FromOldAddr(pOldAddr);
if(pHook == NULL)
{
return NULL;
} return pHook->pNewAddr;
} void *CAdHookApi::NewAddr2OldAddr(void *pNewAddr)
{
HookMap *pHook = FromNewAddr(pNewAddr);
if(pHook == NULL)
{
return NULL;
} return pHook->pOldAddr;
} CAdHookApi::HookMap *CAdHookApi::FromNewAddr(void *pNewAddr)
{
HookMap *pHook = NULL;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
if(pTemp->pNewAddr == pNewAddr)
{
pHook = pTemp;
break ;
}
} return pHook;
} CAdHookApi::HookMap *CAdHookApi::FromOldAddr(void *pOldAddr)
{
HookMap *pHook = NULL;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
if(pTemp->pOldAddr == pOldAddr)
{
pHook = pTemp;
break ;
}
} return pHook;
} BOOL CAdHookApi::HasHook(HANDLE hHook)
{
BOOL bRet = FALSE;
HookMap *pHook = (HookMap *)hHook;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
if(pTemp == pHook)
{
bRet = TRUE;
break ;
}
} return bRet;
} int CAdHookApi::BeginAll()
{
int nRet = 0;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
BOOL bRet = Begin((HANDLE)pTemp);
if(bRet)
{
nRet ++;
}
} return nRet;
} int CAdHookApi::EndAll()
{
int nRet = 0;
for(int i = 0; i < (int)m_obHooks.size(); i ++)
{
HookMap *pTemp = m_obHooks[i];
BOOL bRet = End((HANDLE)pTemp);
delete pTemp;
if(bRet)
{
nRet ++;
}
}
m_obHooks.clear(); return nRet;
} int CAdHookApi::GetCount()
{
return (int)m_obHooks.size();
} User1 自己注入自己(测试用)
#include "stdafx.h"
#include "AdHookApi.h"
#include <windows.h>
using namespace std; static CAdHookApi AdHookApi; int WINAPI mYMessageBoxW( __in_opt HWND hWnd, __in_opt LPCWSTR lpText, __in_opt LPCWSTR lpCaption, __in UINT uType)
{
//如果是做过滤,记得先关闭掉当前的劫持,然后调用原API(给调用者看,当然这个地方也可以进行参数修改),
//然后再改成劫持的地址 也就是 end(a) do happythings begin(a)
MessageBoxA(NULL ,"B" ,"B" ,MB_OK);
return 0;
} int main()
{
AdHookApi.Add(_T("User32.dll") ,"MessageBoxW" ,mYMessageBoxW);
::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);
AdHookApi.BeginAll();
::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);
AdHookApi.EndAll();
::MessageBoxW(NULL ,L"A" ,L"A" ,MB_OK);
return 0;
} User2 DLL
#include "stdafx.h"
#include "ApiDebugger.h"
#include "AdHookApi.h"
#include <tlhelp32.h>
#include <wincrypt.h>
#include "Common.h" static const char * gCopyright = "ApiDebugger by CodeLive, email : dongfa@yeah.net";
static CAdHookApi gHooks; bool gEnableLogOutput = true; extern "C" APIDEBUGGER const char * ApiDebugger()
{
return gCopyright;
} /////////////////////////////////////////////////////////////////////////////// BOOL WINAPI my_IsDebuggerPresent(VOID)
{
return FALSE;
} int WINAPI my_CompareStringW(LCID Locale, DWORD dwCmpFlags, PCNZWCH lpString1, int cchCount1,
PCNZWCH lpString2,int cchCount2)
{
CAdAutoHookApi autoHook(&gHooks, my_CompareStringW);
logOutput(formatString("ApiDebugger - CompareStringW.\r\n"));
int ret = CompareStringW(Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2);
logOutput(formatString("ApiDebugger - CompareStringW(%S, %S).\r\n", lpString1, lpString2));
return ret;
} BOOL WINAPI my_CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR szContainer, LPCWSTR szProvider,
DWORD dwProvType, DWORD dwFlags)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptAcquireContextW);
BOOL ret = CryptAcquireContextW(phProv, szContainer, szProvider, dwProvType, dwFlags);
logOutput(formatString("ApiDebugger - CryptAcquireContextW(0x%08X, %S, %S, 0x%08X, 0x%08X) : %S.\r\n",
(int)(*phProv),
(szContainer != NULL) ? szContainer : L"NULL",
(szProvider != NULL) ? szProvider : L"NULL",
dwProvType, dwFlags,
ret ? L"TRUE" : L"FALSE"
)); return ret;
} BOOL WINAPI my_CryptImportKey(HCRYPTPROV hProv, CONST BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey,
DWORD dwFlags, HCRYPTKEY *phKey)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptImportKey); BOOL ret = CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey); string hexData = toHexString((const char *)pbData, dwDataLen);
logOutput(formatString("ApiDebugger - CryptImportKey(0x%08X, %s, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",
(int)hProv, hexData.c_str(), (int)hPubKey, dwFlags, (int)(*phKey),
ret ? L"TRUE" : L"FALSE"
)); return ret;
} BOOL WINAPI my_CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptCreateHash);
BOOL ret = CryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);
logOutput(formatString("ApiDebugger - CryptCreateHash(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",
(int)hProv, (int)Algid, (int)hKey, dwFlags, (int)phHash,
ret ? L"TRUE" : L"FALSE"
));
return ret;
} BOOL WINAPI my_CryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptHashData);
BOOL ret = CryptHashData(hHash, pbData, dwDataLen, dwFlags);
string hexData = toHexString((const char *)pbData, dwDataLen);
logOutput(formatString("ApiDebugger - CryptHashData(0x%08X, %s, 0x%08X) : %S.\r\n",
(int)hHash, hexData.c_str(), dwFlags,
ret ? L"TRUE" : L"FALSE"
));
return ret;
} BOOL WINAPI my_CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptDeriveKey);
BOOL ret = CryptDeriveKey(hProv, Algid, hBaseData, dwFlags, phKey);
logOutput(formatString("ApiDebugger - CryptDeriveKey(0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X) : %S.\r\n",
(int)hProv, (int)Algid, (int)hBaseData, dwFlags, (int)phKey,
ret ? L"TRUE" : L"FALSE"
));
return ret;
} BOOL WINAPI my_CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,
BYTE *pbData, DWORD *pdwDataLen)
{
CAdAutoHookApi autoHook(&gHooks, my_CryptDecrypt); string hexData1 = toHexString((const char *)pbData, *pdwDataLen);
writeDataToFile("CryptDec_IN.bin", pbData, *pdwDataLen);
BOOL ret = CryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
string hexData2 = toHexString((const char *)pbData, *pdwDataLen);
writeDataToFile("CryptDec_OUT.bin", pbData, *pdwDataLen); logOutput(formatString("ApiDebugger - CryptDecrypt(0x%08X, 0x%08X, %S, 0x%08X, %s=>%s) : %S.\r\n",
(int)hKey, (int)hHash, Final ? L"TRUE" : L"FALSE",
dwFlags, hexData1.c_str(), hexData2.c_str(),
ret ? L"TRUE" : L"FALSE"
));
return ret;
} typedef int (__cdecl *sub_4026B0_func)(BYTE *pbData); // 004026B0 ;
static int my_sub_4026B0(BYTE *pbData)
{
CAdAutoHookApi autoHook(&gHooks, my_sub_4026B0);
sub_4026B0_func sub_4026B0 = (sub_4026B0_func)(0x004026B0);
string hexData1 = toHexString((const char *)pbData, strlen((const char *)pbData));
int ret = sub_4026B0(pbData);
string hexData2 = toHexString((const char *)pbData, strlen((const char *)pbData)); logOutput(formatString("ApiDebugger - sub_4026B0(%s=>%s)",
hexData1.c_str(), hexData2.c_str())); return ret;
} /////////////////////////////////////////////////////////////////////////////// void ApiDebugferShutdown()
{
gHooks.EndAll(); logOutput("ApiDebugger Shutdown.\r\n");
} BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
// gHooks.Add(_T("KERNEL32.DLL"), "IsDebuggerPresent", my_IsDebuggerPresent);
// gHooks.Add(_T("KERNEL32.DLL"), "CompareStringW", my_CompareStringW);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptAcquireContextW", my_CryptAcquireContextW);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptImportKey", my_CryptImportKey);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptCreateHash", my_CryptCreateHash);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptHashData", my_CryptHashData);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptDeriveKey", my_CryptDeriveKey);
gHooks.Add(_T("ADVAPI32.DLL"), "CryptDecrypt", my_CryptDecrypt);
/*
const BYTE verifyData[] = { 0x55, 0x8B, 0xEC, 0x81, 0xEC, 0x2C, 0x01, 0x00, 0x00 };
void *addr = (void *)0x004026B0;
if(gHooks.Add(addr, my_sub_4026B0, verifyData, sizeof(verifyData), 0) != NULL)
{
logOutput(formatString("ApiDebugger - hook sub_4026B0 ok.\r\n"));
}
else
{
logOutput(formatString("ApiDebugger - hook sub_4026B0 failed.\r\n"));
}
*/
gHooks.BeginAll(); logOutput(formatString("ApiDebugger - %s.\r\n", gCopyright));
logOutput("ApiDebugger Loaded.\r\n");
}
break ;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
{
}
break ;
case DLL_PROCESS_DETACH:
{
ApiDebugferShutdown();
logOutput("ApiDebugger Unloaded.\r\n");
}
break;
}
return TRUE;
}

windows-API劫持(API-HOOK)的更多相关文章

  1. Windows 8 动手实验系列教程 实验8:Windows应用商店API

    动手实验 实验 8: Windows应用商店API 2012年9月 简介 编写Windows应用商店应用最令人瞩目的理由之一是您可以方便地将它们发布到Windows应用商店.考虑到世界范围内目前有超过 ...

  2. Windows应用商店API

    Windows应用商店API 动手实验 实验 8: Windows应用商店API 2012年9月 简介 编写Windows应用商店应用最令人瞩目的理由之一是您可以方便地将它们发布到Windows应用商 ...

  3. Windows CE Notification API的使用方法

    1 引言      以Windows CE 为操作系统的掌上电脑(如PocketPC或HPC),除具备PC的功能外,还具备很强的自身控制能力.Windows CE API超越微软其他操作系统的 API ...

  4. Windows系统调用中API的3环部分(依据分析重写ReadProcessMemory函数)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API的3环部分 一.R3环API分析的重 ...

  5. Windows系统调用中API从3环到0环(下)

     Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(下) 如果对API在 ...

  6. Windows系统调用中API从3环到0环(上)

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html Windows系统调用中API从3环到0环(上) 如果对API在三 ...

  7. 【转】asp.net Core 系列【二】—— 使用 ASP.NET Core 和 VS2017 for Windows 创建 Web API

    在本教程中,将生成用于管理“待办事项”列表的 Web API. 不会生成 UI. 概述 以下是将创建的 API: API 描述 请求正文 响应正文 GET /api/todo 获取所有待办事项 无 待 ...

  8. API & Web API

    The follow content refer refers to: Baidu Baike                  : https://baike.baidu.com/item/api/ ...

  9. Delphi常用API,API函数

    auxGetDevCaps API 获取附属设备容量 auxGetNumDevs API 返回附属设备数量 auxGetVolume API 获取当前卷设置 auxOutMessage API 向输出 ...

  10. 好的框架需要好的 API 设计 —— API 设计的六个原则

    说到框架设计,打心底都会觉得很大很宽泛,而 API 设计是框架设计中的重要组成部分.相比于有很多大佬都认可的面向对象的六大原则.23 种常见的设计模式来说,API 设计确实缺少行业公认的原则或者说设计 ...

随机推荐

  1. linux时间问题

    如果遇到创建时间和更新时间,不一致,先将时间调整为一致. 导致不一致的原因可能是时区不对,使用 tzselect ,将时区调整为Asia/Shanghai , cp /usr/share/zonein ...

  2. [DP浅析]线性DP初步 - 2 - 单调队列优化

    目录 #0.0 前置知识 #1.0 简单介绍 #1.1 本质 & 适用范围 #1.2 适用方程 & 条件 #2.0 例题讲解 #2.1 P3572 [POI2014]PTA-Littl ...

  3. Apache配置 4.访问日志

    (1)介绍 访问日志作用很大,不仅可以记录网站的访问情况,还可以在网站有异常发生时帮助我们定位问题. (2)配置 # vi /usr/local/apache2.4/conf/extra/httpd- ...

  4. 什么是IPFS集群?IPFS集群有什么好处?

    IPFS作为区块链不多的创新技术,其热度一直居高不下.IPFS挖矿效率最高的就是集群结构,那么今天我就带着大家了解IPFS的集群挖矿. 什么是集群挖矿?   集群(cluster)就是计算机集群,指在 ...

  5. 通过 ASM 库生成和修改 class 文件

    在 JVM中 Class 文件分析 主要详细讲解了Class文件的格式,并且在上一篇文章中做了总结. 众所周知,JVM 在运行时, 加载并执行class文件, 这个class文件基本上都是由我们所写的 ...

  6. 「HTML+CSS」--自定义按钮样式【003】

    前言 Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 哈哈 自我介绍一下 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入计算机 ...

  7. java例题_47 读取 7 个数(1—50)的整数值,每读取一个值,程序打印出该值个数的*

    1 /*47 [程序 47 打印星号] 2 题目:读取 7 个数(1-50)的整数值,每读取一个值,程序打印出该值个数的*. 3 */ 4 5 /*分析 6 * 1.多次读取---for循环 7 * ...

  8. c++ vector容器浅析

    注:本文章参考 https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html 前言: 最近遇到一个广搜的题,不管怎么试都会暴 然后 ...

  9. [状压DP]子矩阵

    子 矩 阵 子矩阵 子矩阵 题目描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵 如,下面左图中选取第 2 . 4 ...

  10. Python基础(九):字典的使用

    创建字典的5种方式 用{}创建字典 >>> a = {'name':'韩梅梅','age':18,'job':'teacher'} >>> print(a) {'n ...