可选引擎:
nthookengine //支持x64 开源
mhook //支持x64 开源

Detour//x64收费

方法:
本进程HOOK,直接调用HOOK函数;
否则,写成一个DLL,在DLL里HOOK每个函数

然后将该DLL注入到目标进程,达到HOOK目标进程中的函数的目的

MHOOK

//需要直接获取原始函数地址

#include mhook.h
typedef ULONG (WINAPI* _NtOpenProcess)(OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN PVOID ObjectAttributes, IN PCLIENT_ID ClientId );
_NtOpenProcess TrueNtOpenProcess = (_NtOpenProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtOpenProcess");ULONG WINAPI HookNtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN PVOID ObjectAttributes, IN PCLIENT_ID ClientId)
{return TrueNtOpenProcess(ProcessHandle, AccessMask, ObjectAttributes, ClientId);
}Mhook_SetHook((PVOID*)&TrueNtOpenProcess, HookNtOpenProcess);
Mhook_Unhook((PVOID*)&TrueNtOpenProcess);

测试使用mhook-2.1 Hook本进程的OpenProcess

#include "stdafx.h"
#include "mhook-lib/mhook.h"//=========================================================================
// Define _NtOpenProcess so we can dynamically bind to the function
//
typedef struct _CLIENT_ID {DWORD_PTR UniqueProcess;DWORD_PTR UniqueThread;
} CLIENT_ID, *PCLIENT_ID;typedef ULONG (WINAPI* _NtOpenProcess)(OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN PVOID ObjectAttributes, IN PCLIENT_ID ClientId ); //=========================================================================
// Get the current (original) address to the function to be hooked
//
_NtOpenProcess TrueNtOpenProcess = (_NtOpenProcess)GetProcAddress(GetModuleHandle(L"ntdll"), "NtOpenProcess");//=========================================================================
// This is the function that will replace NtOpenProcess once the hook
// is in place
//
ULONG WINAPI HookNtOpenProcess(OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN PVOID ObjectAttributes, IN PCLIENT_ID ClientId)
{printf("***** Call to open process %d\n", ClientId->UniqueProcess);return TrueNtOpenProcess(ProcessHandle, AccessMask, ObjectAttributes, ClientId);
}//=========================================================================
// This is where the work gets done.
//
int wmain(int argc, WCHAR* argv[])
{HANDLE hProc = NULL;// Set the hookif (Mhook_SetHook((PVOID*)&TrueNtOpenProcess, HookNtOpenProcess)) {// Now call OpenProcess and observe NtOpenProcess being redirected// under the hood.hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());if (hProc) {printf("Successfully opened self: %p\n", hProc);CloseHandle(hProc);} else {printf("Could not open self: %d\n", GetLastError());}// Remove the hookMhook_Unhook((PVOID*)&TrueNtOpenProcess);}// Call OpenProces again - this time there won't be a redirection as// the hook has bee removed.hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());if (hProc) {printf("Successfully opened self: %p\n", hProc);CloseHandle(hProc);} else {printf("Could not open self: %d\n", GetLastError());}return 0;
}

NTHookEngine导出函数(对比的进程HOOK 推荐使用这个)

BOOL (__cdecl *HookFunction)(ULONG_PTR OriginalFunction, ULONG_PTR NewFunction);
VOID (__cdecl *UnhookFunction)(ULONG_PTR Function);
ULONG_PTR (__cdecl *GetOriginalFunction)(ULONG_PTR Hook);

NTHookEngineHOOK实现

int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,
WORD wLanguageId, DWORD dwMilliseconds)
{int (WINAPI *pMessageBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds);pMessageBoxW = (int (WINAPI *)(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD))GetOriginalFunction((ULONG_PTR) MyMessageBoxW);return pMessageBoxW(hWnd, lpText, L"Hooked MessageBox",uType, wLanguageId, dwMilliseconds);
}HookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")),"MessageBoxTimeoutW"), (ULONG_PTR) &MyMessageBoxW);UnhookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")), "MessageBoxTimeoutW"));
// NtHookEngine_Test.cpp : Defines the entry point for the application.
//#include "stdafx.h"
#include "NtHookEngine_Test.h"BOOL (__cdecl *HookFunction)(ULONG_PTR OriginalFunction, ULONG_PTR NewFunction);
VOID (__cdecl *UnhookFunction)(ULONG_PTR Function);
ULONG_PTR (__cdecl *GetOriginalFunction)(ULONG_PTR Hook);int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption,UINT uType, WORD wLanguageId, DWORD dwMilliseconds);int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
{//// Retrive hook functions// HMODULE hHookEngineDll = LoadLibrary(_T("NtHookEngine.dll"));HookFunction = (BOOL (__cdecl *)(ULONG_PTR, ULONG_PTR))GetProcAddress(hHookEngineDll, "HookFunction");UnhookFunction = (VOID (__cdecl *)(ULONG_PTR))GetProcAddress(hHookEngineDll, "UnhookFunction");GetOriginalFunction = (ULONG_PTR (__cdecl *)(ULONG_PTR))GetProcAddress(hHookEngineDll, "GetOriginalFunction");if (HookFunction == NULL || UnhookFunction == NULL || GetOriginalFunction == NULL)return 0;//// Hook MessageBoxTimeoutW//HookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")),"MessageBoxTimeoutW"), (ULONG_PTR) &MyMessageBoxW);MessageBox(0, _T("Hi, this is a message box!"), _T("This is the title."), MB_ICONINFORMATION);//// Unhook MessageBoxTimeoutW//UnhookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")), "MessageBoxTimeoutW"));MessageBox(0, _T("Hi, this is a message box!"), _T("This is the title."), MB_ICONINFORMATION);return 0;
}int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,WORD wLanguageId, DWORD dwMilliseconds)
{int (WINAPI *pMessageBoxW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, WORD wLanguageId, DWORD dwMilliseconds);pMessageBoxW = (int (WINAPI *)(HWND, LPCWSTR, LPCWSTR, UINT, WORD, DWORD))GetOriginalFunction((ULONG_PTR) MyMessageBoxW);return pMessageBoxW(hWnd, lpText, L"Hooked MessageBox",uType, wLanguageId, dwMilliseconds);
}

实例:

使用nthookengine Hook目标进程的MessageBox和CreateProcess

被Hook进程 就是普通的进程 里面调用了MessageBox 和 CreateProcess

HOOK DLL代码:

hook.h

// hookdll.cpp : Defines the exported functions for the DLL application.
//#include "stdafx.h"
#include "hookdll.h"// This is an example of an exported variable
HOOKDLL_API int nhookdll=0;// This is an example of an exported function.
HOOKDLL_API int fnhookdll(void)
{return 42;
}// This is the constructor of a class that has been exported.
// see hookdll.h for the class definition
Chookdll::Chookdll()
{return;
}

hook.cpp

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <tchar.h>
#include <stdio.h>BOOL (__cdecl *HookFunction)(ULONG_PTR OriginalFunction, ULONG_PTR NewFunction);
VOID (__cdecl *UnhookFunction)(ULONG_PTR Function);
ULONG_PTR (__cdecl *GetOriginalFunction)(ULONG_PTR Hook);int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption,UINT uType, WORD wLanguageId, DWORD dwMilliseconds);typedef DWORD (WINAPI *CREATPROCESSW)(LPCWSTR lpApplicationName,LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);typedef DWORD (WINAPI *CREATPROCESSA)(LPCSTR lpApplicationName,LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation);typedef int (WINAPI *MESSAGEBOXW)(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption,UINT uType, WORD wLanguageId, DWORD dwMilliseconds);CREATPROCESSW OldCreateProcessW = NULL;
CREATPROCESSA OldCreateProcessA = NULL;
MESSAGEBOXW OldMessageBoxW = NULL;int WINAPI MyMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType,WORD wLanguageId, DWORD dwMilliseconds)
{return OldMessageBoxW(hWnd, lpText, L"Hooked MessageBox",uType, wLanguageId, dwMilliseconds);
}DWORD WINAPI myCreateProcessW(LPCWSTR lpApplicationName,LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation
)
{WCHAR wszInfo[2*MAX_PATH] = {0};_stprintf_s(wszInfo,sizeof(wszInfo)/sizeof(WCHAR),  _T("将要创建进程:%s,阻止吗?"), lpApplicationName);if (MessageBoxW(NULL, wszInfo, lpApplicationName, MB_YESNO)==IDYES){return FALSE;}return OldCreateProcessW(lpApplicationName,lpCommandLine, lpProcessAttributes,lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,lpCurrentDirectory, lpStartupInfo, lpProcessInformation);}DWORD WINAPI myCreateProcessA(LPCSTR lpApplicationName,LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCSTR lpCurrentDirectory,LPSTARTUPINFO lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation
)
{CHAR szInfo[2*MAX_PATH] = {0};sprintf_s(szInfo, sizeof(szInfo), ("将要创建进程:%s,阻止吗?"), lpApplicationName);if (MessageBoxA(NULL, lpApplicationName, lpApplicationName, MB_YESNO)==IDYES){return FALSE;}return OldCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,lpCurrentDirectory, lpStartupInfo, lpProcessInformation);}VOID HookIt(VOID)
{HMODULE hHookEngineDll = LoadLibrary(_T("NtHookEngine.dll"));HookFunction = (BOOL (__cdecl *)(ULONG_PTR, ULONG_PTR))GetProcAddress(hHookEngineDll, "HookFunction");UnhookFunction = (VOID (__cdecl *)(ULONG_PTR))GetProcAddress(hHookEngineDll, "UnhookFunction");GetOriginalFunction = (ULONG_PTR (__cdecl *)(ULONG_PTR))GetProcAddress(hHookEngineDll, "GetOriginalFunction");if (HookFunction == NULL || UnhookFunction == NULL || GetOriginalFunction == NULL)return;//// Hook ALL the apis you want here//HookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")),"MessageBoxTimeoutW"), (ULONG_PTR) &MyMessageBoxW);HookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("KERNEL32.DLL")),"CreateProcessA"), (ULONG_PTR) &myCreateProcessA);HookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("KERNEL32.DLL")),"CreateProcessW"), (ULONG_PTR) &myCreateProcessW);// save the original api addressOldCreateProcessW = (CREATPROCESSW) GetOriginalFunction((ULONG_PTR) myCreateProcessW);OldCreateProcessA = (CREATPROCESSA) GetOriginalFunction((ULONG_PTR) myCreateProcessA);OldMessageBoxW = (MESSAGEBOXW)GetOriginalFunction((ULONG_PTR) MyMessageBoxW);}
VOID UnHook()
{UnhookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("User32.dll")), "MessageBoxTimeoutW"));UnhookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("KERNEL32.DLL")), "myCreateProcessA"));UnhookFunction((ULONG_PTR) GetProcAddress(LoadLibrary(_T("KERNEL32.DLL")), "myCreateProcessW"));
}
BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:HookIt();break;case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH://UnHook();break;}return TRUE;
}

HooKer的功能就是将dll注入目标进程

// hookerDlg.cpp : 实现文件
//#include "stdafx.h"
#include "hooker.h"
#include "hookerDlg.h"
#include <tchar.h>#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialog
{
public:CAboutDlg();// 对话框数据enum { IDD = IDD_ABOUTBOX };protected:virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持// 实现
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialog::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()// ChookerDlg 对话框ChookerDlg::ChookerDlg(CWnd* pParent /*=NULL*/): CDialog(ChookerDlg::IDD, pParent), m_dwPid(0)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void ChookerDlg::DoDataExchange(CDataExchange* pDX)
{CDialog::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT_PID, m_dwPid);
}BEGIN_MESSAGE_MAP(ChookerDlg, CDialog)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()//}}AFX_MSG_MAPON_BN_CLICKED(IDOK, &ChookerDlg::OnBnClickedOk)
END_MESSAGE_MAP()// ChookerDlg 消息处理程序BOOL ChookerDlg::OnInitDialog()
{CDialog::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);            // 设置大图标SetIcon(m_hIcon, FALSE);        // 设置小图标// TODO: 在此添加额外的初始化代码return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}void ChookerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。void ChookerDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR ChookerDlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}BOOL AddDebugPrivilege(void)
{TOKEN_PRIVILEGES tp;LUID luid;HANDLE hToken;if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid)){return FALSE;}tp.PrivilegeCount = 1;tp.Privileges[0].Luid=luid;tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken)){return FALSE;}if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL)){return FALSE;}return TRUE;
} int InjectDll( HANDLE hProcess, TCHAR* szLibPath)
{HANDLE hThread;void*  pLibRemote = 0;DWORD  hLibModule = 0;HMODULE hKernel32 = ::GetModuleHandle(_T("Kernel32"));LPTHREAD_START_ROUTINE pLoadFunc = NULL;pLoadFunc = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryW");if (szLibPath == NULL ||hProcess == NULL ||pLoadFunc == NULL){return FALSE;}pLibRemote = ::VirtualAllocEx( hProcess, NULL, (_tcslen(szLibPath) + 1)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );if( pLibRemote == NULL )return false;::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,(_tcslen(szLibPath) + 1)*sizeof(TCHAR),NULL);hThread = ::CreateRemoteThread( hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pLoadFunc, pLibRemote, 0, NULL );if( hThread == NULL )goto JUMP;DWORD dwError = GetLastError();::WaitForSingleObject( hThread, INFINITE );dwError = GetLastError();::GetExitCodeThread( hThread, &hLibModule );::CloseHandle( hThread );JUMP:    ::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );if( hLibModule == NULL )return false;return hLibModule;
}void ChookerDlg::OnBnClickedOk()
{//LoadLibraryW(_T("hookdll.dll"));AddDebugPrivilege();UpdateData(TRUE);//MessageBox(_T("Failed"));HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE  | PROCESS_VM_READ,FALSE, m_dwPid);if (hProcess == NULL){MessageBox(_T("Failed"));return;}InjectDll(hProcess, _T("hookdll.dll"));//(CButton*)GetDlgItem(IDOK)->EnableWindow(FALSE);//OnOK();
}

需要注意的时,此时应将NtHookEngine编译出来的NtHookEngine.dll放置目标运行目录下(或者使用全路径,推荐使用全路径,因为如果只是文件名的话,程序会先去系统变量path里面找有没有这个镜像的目录,如果有就加载,这样很容易被劫持)

效果如下:

未HOOK前:

正常MessageBox 和 创建一个cmd

HOOK后:

标题被改了,创建进程的时候要询问了

HOOK Engine (nthookengine.mhook)相关推荐

  1. linux 系统调用 hook 总结

    1. 系统调用Hook简介 系统调用属于一种软中断机制(内中断陷阱),它有操作系统提供的功能入口(sys_call)以及CPU提供的硬件支持(int 3 trap)共同完成. 我们必须要明白,Hook ...

  2. Linux系统调用Hook姿势总结

    相关学习资料 http://xiaonieblog.com/?post=121 http://hbprotoss.github.io/posts/li-yong-ld_preloadjin-xing- ...

  3. 高级Linux Kernel Inline Hook技术分析与实现

    2019独角兽企业重金招聘Python工程师标准>>> ==Ph4nt0m Security Team==Issue 0x03, Phile #0x03 of 0x07|=----- ...

  4. linux 进程 inline hook,高级Linux Kernel Inline Hook技术分析与实现 -电脑资料

    ==Ph4nt0m Security Team== Issue 0x03, Phile #0x03 of 0x07 |=---------------------------------------- ...

  5. Hook Com接口函数

    标 题:  [原创]COM接口函数通用Hook方法 作 者: zhangluduo 时 间: 2014-12-08,22:34:20 链 接: http://bbs.pediy.com/showthr ...

  6. linux系统调用挂钩方法总结

    相关学习资料 http://xiaonieblog.com/?post=121 http://hbprotoss.github.io/posts/li-yong-ld_preloadjin-xing- ...

  7. Win64 驱动内核编程-23.Ring0 InLineHook 和UnHook

    Ring0 InLineHook 和UnHook 如果是要在R0里hook,作者的建议是InLine HOOK,毕竟SSDT HOOK 和 SHADOW SSDT HOOK比较麻烦,不好修改.目前R3 ...

  8. Kronos银行木马的前世今生

    本文讲的是Kronos银行木马的前世今生, 还记得WannaCry事件中发现kill-switch,从而阻止了全球10万多台计算机免遭勒索病毒感染的Marcus Hutchins小英雄吗?然而,根据日 ...

  9. Google App Engine技术架构之Google App Engine的简介

    通过前面两篇Google的核心技术和Google整体架构猜想,大家应该对Google强大的基础设施有一定的了解.本篇开始介绍构筑在这强大基础设施之上的Google App Engine. Google ...

最新文章

  1. java kafka分布式_Kafka分布式消息系统
  2. 计算php代码执行时间长短的类
  3. .Net(C#)用正则表达式清除HTML标签(包括script和style),保留纯本文(UEdit中编写的内容上传到数据库)...
  4. 2018年江苏省计算机小高考,江苏2018年小高考成绩查询系统网站入口:江苏省教育考试院...
  5. SRS 启动正常,拉流没画面,看SRS日志报错 srs is already running
  6. 信息学奥赛一本通(1074:津津的储蓄计划)
  7. Elasticsearch Java API四种实现方式
  8. Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序
  9. can not be used when making a shared object; recompile with -fPIC
  10. sqlserver 触发器语法
  11. MATLAB卷积动画演示
  12. Eclipse 最佳字体 推荐
  13. JAVA版本8u171与8u172的区别
  14. php 三个点的用法 function fun (...$arr){}
  15. 百闻牌服务器维护,阴阳师百闻牌一直进不去 无法进入游戏解决方法
  16. 基础算法:Hanoi塔(递归)
  17. qq互动视频页面加载失败_腾讯视频互动视频 | 创作指南
  18. 微信小程序 lookup 联表查询
  19. 「医疗行业」DevExpress助力上海一院HIS系统稳定升级
  20. 美图php面试题目,据说是雅虎的一份PHP面试题附答案

热门文章

  1. JS读取和导出Excel示例(基于js-xlsx)
  2. 羊皮卷-gt;羊皮卷之六(世界上最伟大的推销员)
  3. java 流 压缩 开源_java压缩归档算法开源框架工具 compress
  4. 静思:将“找工作”的核心放一放
  5. 实在RPA专家课:AI+RPA如何赋能电商的数智化升级
  6. vc鼠标消息与键盘消息
  7. 设计原则之里氏替换原则详解
  8. 软考高级-系统架构设计师 经验总结
  9. ESP32 GPIO
  10. SylixOS中的线程【20】--- 线程记事本