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. Kubernetes 实战 —— 02. 开始使用 Kubernetes 和 Docker

    创建.运行及共享容器镜像 P23 运行容器 P24 运行 P24 可以运行 Docker 客户端可执行文件来执行各种 Docker 命令.例如:可以试着从 Docker Hub 的公共镜像仓库拉取.运 ...

  2. 【python+selenium的web自动化】- 8种元素定位方式详解

    ​ 我们在做WEB自动化时,最根本的就是操作页面上的各种元素,而操作的基础便是元素的定位,只有准确地定位到唯一元素才能进行后续的自动化控制,下面将对各种元素定位方式进行总结归纳. ​ 说明:以下操作统 ...

  3. FreeBSD 虚拟网卡 网桥 路由 映射

    网关与路由 netstat -r Routing tables #路由表 Destination Gateway Flags Refs Use Netif Expire 目的地 网关 状态 接口 超时 ...

  4. P2516 [HAOI2010]最长公共子序列 题解(LCS)

    题目链接 最长公共子序列 解题思路 第一思路: 1.用\(length[i][j]\)表示\(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串长度 2.用\(num[i][ ...

  5. apk签名、包名

    //通过各手机管理软件,如如360.豌豆荚等查看 //使用命令行,可以查看到permission.packagename.title.versionCode等 aapt dump badging ~/ ...

  6. 10、Spring教程之整合MyBatis

    1.步骤 1.导入相关jar包 junit <dependency> <groupId>junit</groupId> <artifactId>juni ...

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

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

  8. thinkphp 5.1框架利用及rce分析

    前言 上个学期钻研web渗透的时候接触过几个tp的框架,但那时候还没有写blog的习惯,也没有记录下来,昨天在做ctf的时候正好碰到了一个tp的框架,想起来就复现一下 正文 进入网站,标准笑脸,老tp ...

  9. Java中的三大特性 - 超详细篇

    前言 大家好啊,我是汤圆,今天给大家带来的是<Java中的三大特性 - 超详细篇>,希望对大家有帮助,谢谢 这一节的内容可能有点多,大家可以选择性的来看 简介 Java的三大特性:封装.继 ...

  10. Jenkins-k8s-helm-eureka-harbor-githab-mysql-nfs微服务发布平台实战

    基于 K8S 构建 Jenkins 微服务发布平台 实现汇总: 发布流程设计讲解 准备基础环境 K8s环境(部署Ingress Controller,CoreDNS,Calico/Flannel) 部 ...