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. Redis的常用淘汰策略以及算法实现

    一.Redis的内存配置 1,Redis配置内存为多少合适? 默认:如果不设置最大内存大小或者设置最大内存大小为0,在64为操作系统下不限制内存大小,在32位操作系统下最多使用3GB内存. 极限情况: ...

  2. MySQL入门(5)——运算符

    MySQL入门(5)--运算符 算术运算符 MySQL支持的算数运算符包括加.减.乘.除.求余. 符号 作用 + 加法运算 - 减法运算 * 乘法运算 / 除法运算 % 求余运算 DIV 除法运算,返 ...

  3. Django1和2的区别

    一.路由的区别 1.Django1中的url from django.conf.urls import url # 使用url关键字 urlpatterns = [ url('article-(\d+ ...

  4. 攻防世界 reverse EASYHOOK

    EASYHOOK XCTF 4th-WHCTF-2017 1 data=[ 0x61, 0x6A, 0x79, 0x67, 0x6B, 0x46, 0x6D, 0x2E, 0x7F, 0x5F, 2 ...

  5. .Net Core3.1中SameSite的使用方法、遇到的问题以及解决办法

    一.关于SameSite的介绍 1.  什么是SameSite? SameSite是浏览器请求中Set-Cookie响应头新增的一种属性,它用来标明这个 cookie 是否是"同站 cook ...

  6. java例题 判断一个数能被几个9整除

    有点懵,被几个9整除,我理解的是n=n/9能整除几次,代码如下: 1 /*45 [程序 45 被 9 整除] 2 题目:判断一个数能被几个 9 整除 3 */ 4 5 /*分析 6 * 1.用whil ...

  7. 学习一下 SpringCloud (六)-- 注册中心与配置中心 Nacos、网关 Gateway

    (1) 相关博文地址: 学习一下 SpringCloud (一)-- 从单体架构到微服务架构.代码拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105 ...

  8. 量体裁衣方得最优解:聊聊页面静态化架构和二级CDN建设

    量体裁衣方得最优解:聊聊页面静态化架构和二级CDN建设 上期文章中我们介绍了CDN和云存储的实践,以及云生态的崛起之路,今天,我们继续聊一聊CDN. 我们通常意义上讲的CDN,更多的是针对静态资源类的 ...

  9. var=value?export前后差在哪?-- Shell十三问<第五问>

    var=value?export前后差在哪?-- Shell十三问<第五问> 这次让我们暂时丢开 command line ,先来了解一下 bash 变量(variable)吧.所谓的 变 ...

  10. [DFS]特殊的质数肋骨

    特殊的质数肋骨 时间限制:1000MS----内存限制:256000KB 题目描述 农民约翰母牛总是产生最好的肋骨. 你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们. 农民约翰确定他卖给买 ...