22.4 使用远程线程来注入DLL

22.4.1 概述

(1)远程线程注入是指一个进程在另一个进程中创建线程,然后载入我们编写的DLL,并执行该DLL代码的技术。其基本思路是通过CreateRemoteThread创建一个远程线程,并将LoadLibrary函数作为该线程函数来启动线程,同时将Dll文件名作为线程函数的参数传入。大致执过程如下:CreateRemoteThread()→LoadLibrary()→DllMain()。

(2)核心函数:CreateRemoteThread

参数

说明

HANDLE hProcess

要创建远程线程的进程句柄。除了这参数外,CreateRemoteThread与CreateThread函数参数含义完全相同!

PSECURITY_ATTRIBUTES psa

用于定义新线程的安全属性,这里设为NULL采用默认值即可

DWORD dwStackSize

初始化线程堆栈大小,NULL为默认大小

PTHREAD_START_ROUTINE pfnStartAddr

线程函数的地址,这里传入LoadLibrary函数的地址,但它须在远程进程的地址空间中,因为它是让远程线程调用的。如何获得远程进程中这函数地址,可参考后面内容。

PVOID pvParam

线程函数参数,这里一般是DLL文件名,但这个名称须保存在远程进程的地址空间中,这也是个比较棘手的问题。

DWORD fdwCreate

函数表示创建线程后线程的运行状态

PDWORD pdwThreadId

返回线程ID,不关心可以设为NULL不返回

备注:使用这个函数关键要解决三个参数问题:①获得远程线程的进程句柄,而且要确保相应权限(如Debug权限);②获取远程进程中线程函数的开始地址,而非本地地址;③向远程线程成功传入DLL路径字符串。

(3)其他函数

  ①在远程进程中分配/释放内存:VirtualAllocEx/VirtualFreeEx

  ②对远程进程地址空间进行读写:ReadProcessMemory/WriteProcessMemory

22.4.2 获取LoadLibrary函数的远程地址

(1)LoadLibrary要作为远程线程函数来使用,必须满足两个条件:

  ①该函数符合线程函数的原型。(查看MSDN,他们有相同的调用约定,都有一个参数和一个返回值。至于类型不同,可以通过强转类型得到,所以该条件满足)

  ②该函数存在于远程线程地址空间内。这一点也可以保证的,因为LoadLibrary函数位于Kernel32.dll中,对于Windows系统而言,本地进程和远程进程中的Kernel32.dll被映射到地址空间的同一内存地址,因而只要通过GetProcAddress获取本地进程中LoadLibrary的地址,在远程进程中也同样是这个地址,可以直接传给CreateRemoteThread。

(2)LoadLibrary是被定义为一个宏,而不是函数。有两个版本LoadLibraryA和LoadLibraryW。

(3)为什么CreateRemoteThread的pfnStartAddr参数不能直接写成LoadLibrary W(或A),而要使用GetProcAddress获得的LoadLibary函数的地址

  ①LoadLibrary W(或A)是Kernel32.dll中的一个导出函数,但我们的Dll中直接引用该函数时,会在Dll的导入表记录下来。我们都知道导入函数的真实地址是在DLL加载的时候才能确定的,加载程序会从导入表中取得导入函数名,在被加载到进程地址空间后,会计算出该函数地真实地址,然后填入导入表(IAT)相应的位置。这种函数在编译期无法知道切确的地址,所以被编译成CALL DWORD PTR[XXXXXXXX]之类的代码,中括号中的数值虽然是一个确定的数值,但并不是导入函数的真实地址(形如CALL XXXXXXXX),而是一个子程序的地址,该程序被称为转换函数(Thunk)。【顺便说一下,这也是为什么在声明一个导入函数时要加上__declspec(dllimport)前缀的原因,因为编译器无法区分应用程序是对一般函数调用还是对导入函数调用。当加上这个前缀时,编译器会认为此函数来自导入函数,就会产生CALL DWORD PTR[XXXXXXXX]的指令,而不是CALL XXXXXXXX。】

  ②当程序调用导入函数时,编译器会处理成先调用转换函数,然后转换函数从IAT表中获得导入函数的真实地址,再调用相应的地址。所以如果将CreateRemoteThread的pfnStartAddr参数写成LoadLibraryW(或A),这里地址将被编译成转换函数的地址,而不是LoadLibrary的真实地址。

22.4.3 将DLL的路径字符串存放到远程的地址空间中

(1)如果直接向CreateRemoteThread()传入DLL路径,如”C:\\MyDLL.dll”那么实际向远程线程传递的是一个本地的指针值,这个值在远程进程的地址空间中是没有意义的

(2)可以使用VirtualAllocEx()函数在远程进程中先分配一段空间,然后再使用WriteProcessMemory将DLL路径字符串复制到远程进程的地址空间中去,最后将该远程内存的指针传给CreateRemoteThead相应的参数。

24.4.4 总结使用远程线程注入DLL的步骤

  ①用VirtualAllocEx函数在远程进程的地址空间中分配一块内存。

  ②用WriteProcessMemory函数反映Dll的路径名复制到第1步分配的内存中

  ③用GetProcAddress函数来得到LoadLibrary W(或A)函数在Kernel32.dll的真实地址。

  ④用CreateRemoteThread函数在远程进程中创建一个线程,让新线程调用正确的LoadLibrary函数并在参数中传入第1步分配的内存地址。这时,DLL己经被注入到远程进程的地址空间中,DLL的DllMain函数会收到DLL_PROCESS_ATTACH通知并县城可以执行我们想要执行的代码。当DllMain返回时,远程线程会从线程函数(LoadLibraryW/A)调用返回到线程启动函数RtlUserThreadStart(该函数的实现可参考第6章),最后调用ExitThread使远程线程终止。

  ⑤此时远程进程中那块在第1步分配的内存还在,DLL也还在远程进程的地址空间中。这里只需调用VirtualFreeEx就可以释放远程进程的内存。

  ⑥但DLL的释放,要先通过GetProcAddress获得FreeLibrary的地址,然后再通过CreateRemoteThread在远程进程中创建一个线程,让该线程调用FreeLibrary,pvParam参数传入远程DLL中句柄。

【InjectLibrary示例程序】

        

注入进程本身                                                                                    注入“记事本”程序

//ImgWalk动态库,这个DLL用来检测被注入的进程中当前载入的各个模块名称

/************************************************************************
Module: ImgWalk.cpp
Notices: Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
************************************************************************/ #include "../../CommonFiles/CmnHdr.h"
#include <tchar.h> //////////////////////////////////////////////////////////////////////////
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID fImpload){
if (fdwReason == DLL_PROCESS_ATTACH){
char szBuf[MAX_PATH * ] = { }; PBYTE pb = NULL;
MEMORY_BASIC_INFORMATION mbi;
while (VirtualQuery(pb, &mbi, sizeof(mbi)) == sizeof(mbi)){
int nLen;
char szModName[MAX_PATH]; if (mbi.State == MEM_FREE)
mbi.AllocationBase = mbi.BaseAddress; if ((mbi.AllocationBase == hInstDll) || //该区域包含该DLL,则隐藏掉该DLL,不显示在后面对话框中
(mbi.AllocationBase !=mbi.BaseAddress || //块不是区域的开始地址
(mbi.AllocationBase == NULL))){ //区域地址为NULL
nLen = ;
} else{
nLen = GetModuleFileNameA((HINSTANCE)mbi.AllocationBase,
szModName, _countof(szModName));
} if (nLen > ){
wsprintfA(strchr(szBuf, ),//找到第一个0
"\n%p-%s",
mbi.AllocationBase, szModName);
} pb += mbi.RegionSize;
} //注意:正常情况下,不应该在DllMain里显示一个对话框,因为
//装载器被锁。但为了程序简单化,这里违返了这个规则
chMB(&szBuf[]); //从1开始,因为 "\n%p-%s",表示szBuf[0]为换行符
}
return (TRUE);
}

//InjLib,创建远程线程用于将上述的DLL注入到指定的进程中去

 /************************************************************************
Module: InjLib.cpp
Notices: Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
************************************************************************/ #include "../../CommonFiles/CmnHdr.h" #include <tchar.h>
#include <malloc.h> // For alloca
#include <strsafe.h>
#include <TlHelp32.h>
#include "resource.h" //////////////////////////////////////////////////////////////////////////
#ifdef UNICODE
#define InjectLib InjectLibW
#define EjectLib EjectLibW
#else
#define InjectLib InjectLibA
#define EjectLib EjectLibA
#endif //////////////////////////////////////////////////////////////////////////
//创建远程线程并注入DLL
//参数:dwProcessID——进程ID
// pszLibFile ——要注入的DLL路径(含名称)
BOOL WINAPI InjectLibW(DWORD dwProcessId, PCWSTR pszLibFile){
BOOL bOk = FALSE; //假设注入失败
HANDLE hProcess = NULL, hThread = NULL;
PWSTR pszLibFileRemote = NULL; __try{
//获取目标进程句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION |
PROCESS_CREATE_THREAD | //For CreateRemoteThread
PROCESS_VM_OPERATION | //For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE, //For WriteProcessMemory
FALSE,dwProcessId); if (hProcess == NULL) __leave; //计算存储Dll路径名所需的字节数
int cch = + lstrlen(pszLibFile);//字符个数,因strlen不含\0,所以加1为\0预留
int cb = cch*sizeof(wchar_t); //为远程进程分配一个内存以存储DLL路径名称
pszLibFileRemote = (PWSTR)
VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
if (pszLibFileRemote == NULL) __leave; //复制DLL路径名称到远程进程的内存中
if (!WriteProcessMemory(hProcess, pszLibFileRemote,
(PVOID)pszLibFile, cb, NULL)) __leave; //获取LoadLibraryW在Kernel32.dll中的地址
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW"); if (pfnThreadRtn == NULL) __leave; //创建远程线程调用LoadLibraryW(DllPathName);
hThread = CreateRemoteThread(hProcess,
NULL, ,
pfnThreadRtn, //LoadLibraryW(远程进程地址空间中)
pszLibFileRemote, //Dll路径名(远程进程地址空间中)
, NULL);
if (hThread == NULL) __leave; //等待远程线程结束
WaitForSingleObject(hThread, INFINITE); bOk = TRUE; //注入成功
}
__finally{
//释放用于保存Dll路径名称的内存
if (pszLibFileRemote != NULL)
VirtualFreeEx(hProcess, pszLibFileRemote, , MEM_RELEASE); if (hThread != NULL)
CloseHandle(hThread); if (hProcess != NULL)
CloseHandle(hProcess);
}
return (bOk);
} //////////////////////////////////////////////////////////////////////////
BOOL WINAPI InjectLibA(DWORD dwProcessId, PCSTR pszLibFile){
//分配一个栈内存(无需手用释放),用于存储Unicode版本的路径名
SIZE_T cchSize = lstrlenA(pszLibFile) + ;//字符个数,含\0
PWSTR pszLibFileW = (PWSTR)
_alloca(cchSize*sizeof(wchar_t)); //将ANSI路径名转化为等价的Unicode版本
StringCchPrintfW(pszLibFileW, cchSize, L"%S", pszLibFile); return (InjectLibW(dwProcessId, pszLibFileW));
} //////////////////////////////////////////////////////////////////////////
//将DLL从进程地址空间中撤销
//先根据DLL文件名,在进程加载的模块中查找是否该DLL己被加载
//如果被加载,记下这个DLL的句柄。然后创建远程线程去调用FreeLibrary卸载
BOOL WINAPI EjectLibW(DWORD dwProcessId, PCWSTR pszLibFile){
BOOL bOk = FALSE; //假定撤销失败
HANDLE hthSnapshot = NULL;
HANDLE hProcess = NULL, hThread = NULL;
__try{
//抓取进程快照
hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,//指定进程中加载的所有模块
dwProcessId); //获得Unicode版本的目标DLL库句柄
MODULEENTRY32W me = { sizeof(me) };
BOOL bFound = FALSE;
BOOL bMoreMods = Module32FirstW(hthSnapshot, &me); //Unicode版本
for (; bMoreMods;bMoreMods = Module32NextW(hthSnapshot,&me)){
bFound = (_wcsicmp(me.szModule, pszLibFile) == ) ||
(_wcsicmp(me.szExePath, pszLibFile) == );
if (bFound)
break;
}
if (!bFound) __leave; //获得目标进程的句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION |
PROCESS_CREATE_THREAD | //For CreateRemoteThread
PROCESS_VM_OPERATION, //For VirtualAllocEx/VirtualFreeEx
FALSE, dwProcessId);
if (hProcess == NULL) __leave; //获取FreeLibrary在Kernel32.dll中的地址
PTHREAD_START_ROUTINE pfnThreadRtn = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
if (pfnThreadRtn == NULL) __leave; //创建远程线程
hThread = CreateRemoteThread(hProcess,
NULL, ,
pfnThreadRtn, //FreeLibrary(远程进程地址空间中)
me.modBaseAddr,
, NULL);
if (hThread == NULL) __leave; //等待远程线程结束
WaitForSingleObject(hThread, INFINITE); bOk = TRUE; //撤销成功 }
__finally{ if (hthSnapshot != NULL)
CloseHandle(hthSnapshot); if (hThread != NULL)
CloseHandle(hThread); if (hProcess != NULL)
CloseHandle(hProcess);
} return (bOk);
} //////////////////////////////////////////////////////////////////////////
BOOL WINAPI EjectLibA(DWORD dwProcessId, PCSTR pszLibFile){
//分配一个栈内存(无需手用释放),用于存储Unicode版本的路径名
SIZE_T cchSize = lstrlenA(pszLibFile) + ;//字符个数,含\0
PWSTR pszLibFileW = (PWSTR)
_alloca(cchSize*sizeof(wchar_t)); //将ANSI路径名转化为等价的Unicode版本
StringCchPrintfW(pszLibFileW, cchSize, L"%S", pszLibFile); return (EjectLibW(dwProcessId, pszLibFileW));
} //////////////////////////////////////////////////////////////////////////
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){
chSETDLGICONS(hwnd, IDI_INJLIB);
return (TRUE);
}
//////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtrl, UINT codeNotity){
switch (id)
{
case IDCANCEL:
EndDialog(hwnd, id);
break; case IDC_INJECT:
DWORD dwProcessId = GetDlgItemInt(hwnd, IDC_PROCESSID, NULL, FALSE);
if (dwProcessId == ){
//如果dwProcessId为0,表示注入到本地进程
dwProcessId = GetCurrentProcessId();
} TCHAR szLibFile[MAX_PATH];
GetModuleFileName(NULL, szLibFile, _countof(szLibFile)); //获得当前进程的完整路径
PTSTR pFilename = _tcsrchr(szLibFile, TEXT('\\')) + ;
_tcscpy_s(pFilename, _countof(szLibFile) - (pFilename - szLibFile),
TEXT("22_ImgWalk.DLL")); if (InjectLib(dwProcessId,szLibFile)){
chVERIFY(EjectLib(dwProcessId, szLibFile));
chMB("DLL注入/撤消成功!");
} else{
chMB("DLL注入/撤消失败!");
} break;
}
} //////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
switch (uMsg)
{
chHANDLE_DLGMSG(hWnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hWnd, WM_COMMAND, Dlg_OnCommand);
}
return (FALSE);
} //////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(HINSTANCE hInstExe, HINSTANCE, PTSTR pszCmdLine, int){
DialogBox(hInstExe, MAKEINTRESOURCE(IDD_INJLIB), NULL, Dlg_Proc);
return ();
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 22_InjLib.rc 使用
//
#define IDD_INJLIB 1
#define IDC_INJECT 100
#define IDC_PROCESSID 101
#define IDI_INJLIB 101 // Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

//.rc文件

// Microsoft Visual C++ generated resource script.
//
#include "resource.h" #define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h" /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS /////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED /////////////////////////////////////////////////////////////////////////////
//
// Icon
// // Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_INJLIB ICON "InjLib.ico" #ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
// TEXTINCLUDE
BEGIN
"resource.h\0"
END TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END #endif // APSTUDIO_INVOKED /////////////////////////////////////////////////////////////////////////////
//
// Dialog
// IDD_INJLIB DIALOGEX , , ,
STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "远程线程注入DLL"
FONT , "MS Shell Dlg", , , 0x0
BEGIN
LTEXT "进程ID(10进制):",-,,,,
EDITTEXT IDC_PROCESSID,,,,,ES_AUTOHSCROLL
DEFPUSHBUTTON "注入",IDC_INJECT,,,,,WS_GROUP
END /////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
// #ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_INJLIB, DIALOG
BEGIN
END
END
#endif // APSTUDIO_INVOKED #endif // 中文(简体,中国) resources
///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
// /////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

22.5 使用木马DLL来注入DLL

(1)如果某个进程必须载入一个DLL(如xyz.dll)。则可以创建自己的DLL并给他起同样的名称,然后进行替换。并将旧的xyz.dll改为别的名称(如abc.dll)。

(2)在我们的xyz.dll的内部,导出原来xyz.dll导出的所有符号。(用函数转发器导为abc.dll相应的符号)。

(3)在我们的xyz.dll内部,可以增加一些我们自己的代码,以便以我们操作被注入的进程。

第22章 DLL注入和API拦截(2)的更多相关文章

  1. 第22章 DLL注入和API拦截(3)

    22.6 API拦截的一个例子 22.6.1 通过覆盖代码来拦截API (1)实现过程 ①在内存中对要拦截的函数(假设是Kernel32.dll中的ExitProcess)进行定位,从而得到它的内存地 ...

  2. 第22章 DLL注入和API拦截(1)

    22.1 注入的一个例子(跨进程子类化窗口) ①子类化窗口可以改变窗口的行为,让发往该窗口的消息重新发到我们指定的过程来处理.但这种行为只能在本进程中(如A),对于从一个进程(如B)去子类化另一个进程 ...

  3. DLL注入_拦截技术之Hook方式

    后卫大师教你进程注入 首先提一下,由于文章完全是我手写,所以打不了太多,请包含,由于我已经提供了源代码,所以我在这里详细讲一下理论,至于想看代码的下载代码就可以了.代码中关于注入的部分做了详细的注释. ...

  4. Win32环境下代码注入与API钩子的实现(转)

    本文详细的介绍了在Visual Studio(以下简称VS)下实现API钩子的编程方法,阅读本文需要基础:有操作系统的基本知识(进程管理,内存管理),会在VS下编写和调试Win32应用程序和动态链接库 ...

  5. Win32环境下代码注入与API钩子的实现

    本文详细的介绍了在Visual Studio(以下简称VS)下实现API钩子的编程方法,阅读本文需要基础:有操作系统的基本知识(进程管理,内存管理),会在VS下编写和调试Win32应用程序和动态链接库 ...

  6. 20145319 《网络渗透》免考—API拦截技术

    20145319 <网络渗透>免考-API拦截技术 概述 本次实验在window环境下进行,主要通过编写hook代码和注入程序,将我们的hook代码通过dll文件的形式注入到目标中,拦截其 ...

  7. <ReversingEngineering>关于windows32位系统下的dll注入技术经验汇

    上个学期把自己闷在图书馆一直在看关于逆向工程技术方面的书,从入门到初级,现在也敢说自己一条腿已经迈进了这片知识的大门里,因为该博客刚开通先将一些经验记录下来,也是留给自己一方面做个参照. <逆向 ...

  8. DLL注入新姿势:反射式DLL注入研究

    在分析koadic渗透利器时,发现它有一个注入模块,其DLL注入实现方式和一般的注入方式不一样.搜索了一下发现是由HarmanySecurity的Stephen Fewer提出的ReflectiveD ...

  9. Dll注入技术之消息钩子

    转自:黑客反病毒 DLL注入技术之消息钩子注入 消息钩子注入原理是利用Windows 系统中SetWindowsHookEx()这个API,他可以拦截目标进程的消息到指定的DLL中导出的函数,利用这个 ...

随机推荐

  1. HTML · 图片热点,网页划区,拼接,表单

    图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可以完成跳转的效果. 网页划区: 在一个网页里,规划出一个区域用来展示另一个网页的内容. 网页的拼接: 在一个网络页面内,规划出多 ...

  2. viewport的一些事

    整理了下viewport的东西,用脑图画了下

  3. SAP Basis常用事务代码

    事务码 描述(中英文)     SBIT Menu 菜单     SBTA Test background processing 后台处理测试     SBTU Background processi ...

  4. IFeatureCursor.Flush

    IFeatureCursor.Flush Method Flush any outstanding buffered writes to the database. [Visual Basic .NE ...

  5. 【读书笔记】iOS-本地文件和数据安全注意事项

    一,程序文件的安全. 可通过将JavaScript源码时行混淆和加密,防止黑客轻易地阅读和篡改相关的逻辑,也可以防止自己的Web端与Native端的通讯协议泄露. 二,本地数据安全. 对于本地的重要数 ...

  6. UIView简单动画

    UIView动态实现的效果有以下几种: 1.动态改变frame 2.动态改变color 3.动态改变alpha 4.动态改变bounds 首先,我们先看几种BasicView动画 #pragma ma ...

  7. ARC-数据类型需要释放的情况

    // Foundation :  OC// Core Foundation : C语言// Foundation和Core Foundation框架的数据类型可以互相转换的 //NSString *s ...

  8. svn conflict

    安装svn apt-get install subversion 当前两个人都更新版本为version1 A修改了monitor.txt文件 提交后版本为version2 B也修改了monitor.t ...

  9. Profiling MySQL queries from Performance Schema

    转自:http://www.percona.com/blog/2015/04/16/profiling-mysql-queries-from-performance-schema/ When opti ...

  10. 【mysql】使用tpcc-mysql进行压力测试

    Tpcc-mysql是percona基于tpcc衍生出来专用于mysql基准测试的产品 ,可以参见 <高性能MySQL第三版> 一.安装 rpm -Uvh http://dl.fedora ...