admin 发布的文章

一个简单的桩实现类:

#define JMPCODE_LENGTH 5            //x86 平坦内存模式下,绝对跳转指令长度
#define JMPCMD_LENGTH  1            //机械码0xe9长度
#define JMPCMD         0xe9         //对应汇编的jmp指令

//一个简化的打桩类的实现
classXSimpleStub
{
public:explicit XSimpleStub(void* pOrigFunc, void* pNewFunc, bool need_lock_other_thread = false);~XSimpleStub();private://源函数地址 void *str_func_addr;//是否打桩成功 boolis_stub_succ;//是否打桩成功 boolneed_lock_other_thread_;//源指令数据的备份 unsigned charstr_instruct_back[JMPCODE_LENGTH];
};

函数就只有两个函数体,分别如下

#include <tlhelp32.h>BOOL LockOtherThread()
{
DWORD dwCurrPid
=GetCurrentProcessId();
DWORD dwCurrTid
=GetCurrentThreadId();

HANDLE hThread
=NULL;
HANDLE hThreadSnap
=NULL;
THREADENTRY32 te32
= { 0};
te32.dwSize
= sizeof(THREADENTRY32);//遍历线程 if (Thread32First(hThreadSnap, &te32))
{
do{if (te32.th32OwnerProcessID ==dwCurrPid) {if (te32.th32ThreadID !=dwCurrTid){//获取句柄 hThread =OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);if (NULL !=hThread){
SuspendThread(hThread);
}
CloseHandle(hThread);
}
}
}
while (Thread32Next(hThreadSnap, &te32));
}
CloseHandle(hThreadSnap);
returnTRUE;
}

BOOL UnlockOtherThread()
{
DWORD dwCurrPid
=GetCurrentProcessId();
DWORD dwCurrTid
=GetCurrentThreadId();

HANDLE hThread
=NULL;
HANDLE hThreadSnap
=NULL;
THREADENTRY32 te32
= { 0};
te32.dwSize
= sizeof(THREADENTRY32);//遍历线程 if (Thread32First(hThreadSnap, &te32))
{
do{if (te32.th32OwnerProcessID ==dwCurrPid) {if (te32.th32ThreadID !=dwCurrTid){//获取句柄 hThread =OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);if (NULL !=hThread){
ResumeThread(hThread);
}
CloseHandle(hThread);
}
}
}
while (Thread32Next(hThreadSnap, &te32));
}
CloseHandle(hThreadSnap);
returnTRUE;
}
static void __inner_memcpy(unsigned char* pDest, unsigned char* pSrc, unsigned intcount)
{
while(count > 0) {*pDest++ = *pSrc++;
count
--;
}
}

XSimpleStub::XSimpleStub(
void* pOrigFunc, void* pNewFunc, boolneed_lock_other_thread):
str_func_addr(pOrigFunc), is_stub_succ(
false), need_lock_other_thread_(need_lock_other_thread)
{
//源地址、目标地址需要进行一次判定 if (nullptr != pOrigFunc && nullptr !=pNewFunc)
{
DWORD ProtectVar;
//保护属性变量 MEMORY_BASIC_INFORMATION MemInfo; //内存分页属性信息//取得对应内存的原始属性 if (0 != VirtualQuery(pOrigFunc, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
{
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread) {
LockOtherThread();
}
//修改页面为可写 if(VirtualProtect(MemInfo.BaseAddress, MemInfo.RegionSize, PAGE_READWRITE, &MemInfo.Protect))
{
//备份原数据,防止自身需要使用memcpy,不能使用类似接口 __inner_memcpy((unsigned char*)str_instruct_back, (unsigned char*)pOrigFunc, JMPCODE_LENGTH);//修改目标地址指令为 jmp pDestFunc *(unsigned char*)pOrigFunc = JMPCMD; //拦截API,在函数代码段前面注入jmp xxx *(DWORD*)((unsigned char*)pOrigFunc + JMPCMD_LENGTH) = (DWORD)pNewFunc - (DWORD)pOrigFunc -JMPCODE_LENGTH;//改回原属性 VirtualProtect(MemInfo.BaseAddress, MemInfo.RegionSize, MemInfo.Protect, &ProtectVar);//修改后,还需要刷新cache FlushInstructionCache(GetCurrentProcess(), pOrigFunc, JMPCODE_LENGTH);

is_stub_succ
= true;
}
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread) {
UnlockOtherThread();
}
}
}
}

XSimpleStub::
~XSimpleStub()
{
if(is_stub_succ)
{
DWORD TempProtectVar;
//临时保护属性变量 MEMORY_BASIC_INFORMATION MemInfo; //内存分页属性信息 if (0 != VirtualQuery(str_func_addr, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
{
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread_) {
LockOtherThread();
}
//修改页面为可写 if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, PAGE_READWRITE,&MemInfo.Protect))
{
//恢复代码段 __inner_memcpy((unsigned char*)str_func_addr, (unsigned char*)str_instruct_back, JMPCODE_LENGTH);//改回原属性 VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize, MemInfo.Protect,&TempProtectVar);//修改后,还需要刷新cache FlushInstructionCache(GetCurrentProcess(), str_func_addr, JMPCODE_LENGTH);
}
//如果需要锁住所有其他线程,则先执行锁定动作 if(need_lock_other_thread_) {
UnlockOtherThread();
}
}
}

}

 

Linux下一样有类似技术,可以参考IBM的一个文档:

https://www.ibm.com/developerworks/cn/linux/l-knldebug/index.html

这其中的差别在跳转指针的设计上,Linux上,是使用了7个字节,并不需要计算原函数、新函数的地址距离

整个替换流程的实现分为如下几个步骤:

1) 替换指令码:
b8
00 00 00 00 /*movl $0, $eax;这里的$0将被具体替换函数的地址所取代*/
ff e0 /*
jmp*$eax ;跳转函数*/
将上述7个指令码存放在一个字符数组中:
replace_code[
7]

2) 用替换函数的地址覆盖第一条指令中的后面8个0,并保留原来的指令码:
memcpy (orig_code, func,
7);/* 保留原函数的指令码 */ *((long*)&replace_code[1])= (long) replace_func;/* 赋替换函数的地址 */ memcpy (func, replace_code, 7); /* 用新的指令码替换原函数指令码 */

3) 恢复过程用保留的指令码覆盖原函数代码:
memcpy (func, orig_code,
7)

Linux下,实现代码页属性修改使用函数接口:mprotect

 而相应的Linux下线程挂起、恢复使用如下接口:

#include <signal.h>
pthread_kill(ThreadID, SIGSTOP);  // suspend
pthread_kill(ThreadID, SIGCONT);  // resume

通过查看/proc/pid/task得知一个任务下的所有线程数

 

VS2012版本下std::function存在问题,链接:https://stackoverflow.com/questions/13096162/stdfunction-not-compiling-in-vs2012

#include <iostream>
#include <functional>

struct Foo {
    Foo(int num) : num_(num) {}
    void print_add(int i) const { std::cout << num_+i << '\n'; }
    int num_;
};

int main()
{
    // store a call to a member function
    std::function<void(const Foo&, int)> f_add_display = std::mem_fn(&Foo::print_add);
    Foo foo(314159);
    f_add_display(foo, 1);
}

 

 

 

Motherboard name: B365M-PIXIU
BIOS date: 05/24/2019
BIOS version: 1002
ME version: 11.8.65.3590 (1.5M)
GbE version: Not present
Primary LAN MAC: 40B0767D8454
DTS key: Not present
UUID: 536A2E2B2CFE90322E4440B0767D8454
MBSN: 190245622202248

 以下inno setup脚本,实现了:1.水波纹效果 2.安装时检测是否安装其他版本,并在欢迎页面添加文字提示 4.检测安装vcredist_x86.exe  3.卸载时添加提示

; 脚本由 Inno Setup 脚本向导 生成!
; 有关创建 Inno Setup 脚本文件的详细资料请查阅帮助文档!

#define MyAppName "GX_Standardizeddrawing_X64"
#define MyAppVersion "
2.5"
#define MyAppPublisher "ZWSOFT"
#define MyAppURL "www.zwcad.com"
#define MyAppExeName "Gx_standardizeddrawing"
#define shortCutName "广西通信标准化制图"

[Setup]
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (生成新的GUID,点击 工具|在IDE中生成GUID。)
AppId
={{904DF7AD-D92A-4E81-A8ED-F0EB51701FFC}AppName={#shortCutName}AppVersion={#MyAppVersion};AppVerName={#MyAppName} {#MyAppVersion}AppSupportURL={#MyAppURL}AppUpdatesURL={#MyAppURL}DefaultGroupName={#shortCutName}OutputBaseFilename=广西通信插件_V2.5DefaultDirName=D:\{#MyAppName}Compression=lzma
SolidCompression
=yes
UseSetupLdr
=yes
DisableWelcomePage
=no
;WindowVisible
=yes
;LicenseFile
=E:\GitHub\SVN\Project\ZwRQY\ZWRQY_ZWCAD\license.txt
WizardImageFile
=.\WizardImage.bmp
WizardSmallImageFile
=.\WizardSmallImage.bmp
AppPublisher
=ZWSOFT
AppPublisherURL
=http://www.zwcad.com/AppCopyright=Copyright (C) 1998-2019zwsof, Inc.
OutputDir
=.\
;管理员权限
PrivilegesRequired
=admin
Uninstallable
=yes
UninstallDisplayName
={#shortCutName}SetupIconFile=.\Setup\Setup\res\zwcad.ico

;覆盖安装
UsePreviousAppDir
=yes


[Messages]
BeveledLabel
=广州中望龙腾软件股份有限公司

[Languages]
Name: "Chinese"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "
{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone; OnlyBelowVersion: 0,8.1Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "..\OUT\Bin\x64\Release\SysZw\Gx_standardizeddrawing.exe"; DestDir: "
{app}\SysZw"; Flags: ignoreversion; Permissions: authusers-full
Source: "..\OUT\Bin\x64\Release\
*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Permissions: authusers-full
Source: "waterctrl.dll"; Flags: dontcopy
Source: "WizardImage.bmp"; Flags: dontcopy
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion”

[Icons]
Name: "
{group}\{#shortCutName}"; Filename: "{app}\SysZw\{#MyAppExeName}"
Name: "
{group}\{cm:UninstallProgram,{#shortCutName}}"; Filename: "{uninstallexe}"
Name: "
{commondesktop}\{#shortCutName}"; Filename: "{app}\SysZw\{#MyAppExeName}"; Tasks: desktopicon
Name: "
{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppExeName}"; Filename: "{app}\SysZw\{#MyAppExeName}"; Tasks: quicklaunchicon


[Run]
Filename: "
{app}\SysZw\vcredist_x86.exe"; Parameters: /q; WorkingDir: {tmp}; Flags: skipifdoesntexist;StatusMsg: "Installing Microsoft Visual C++Runtime ..."; Check: NeedInstallVC9SP1
;Filename: "
{app}\SysZw\AceRedist.msi"; Parameters: /q; WorkingDir: {tmp}; Flags: skipifdoesntexist; StatusMsg: "Installing Microsoft Access Database Engine 2010Redistributable ...";
Filename: "
{app}\SysZw\msiexec.exe"; Parameters: "/i ""{app}\SysZw\AceRedist.msi"" /quiet";StatusMsg:"Installing Microsoft Access Database Engine 2010Redistributable ..."
Filename: "
{app}\SysZw\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(shortCutName, "&", "&&")}}"; Flags: nowait postinstall skipifsilent

[UninstallDelete]
Name:
{app}; Type: filesandordirs;

[code]
varvc9SP1Missing: Boolean;
vc9SP2Missing: Boolean;
functionInitializeSetup():boolean;var //MykeynotExist:boolean;//ResultCode: Integer;//uicmd: String;
version: Cardinal;
begin {检测是否安装vcredist_x86.exe} if RegQueryDWordValue(HKLM, 'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{196BB40D-1578-3D01-B289-BEFC77A11A1E}', 'Version', version) =falsethen beginvc9SP1Missing :=true;end;//MykeynotExist:=true;//if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{904DF7AD-D92A-4E81-A8ED-F0EB51701FFC}_is1', 'UninstallString', uicmd) then //begin {MyKeynotExist:= false;
Exec(RemoveQuotes(uicmd), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
} // ResultCode := MsgBox('检测到本机已安装其他版本!继续安装将会覆盖本机已安装版本!是否继续安装?', mbConfirmation, MB_YESNO);// if ResultCode = IDNO then // begin // MyKeynotExist:=false;// end;// if ResultCode = IDYES then // begin {Exec(RemoveQuotes(uicmd), '/silent /verysilent /suppressmsgboxes', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);} // MyKeynotExist:=true;// end;//end;// Result:=MykeynotExist

Result:
=true;end;functionInitializeUninstall(): Boolean;beginResult:=true;if MsgBox('卸载将会清空安装目录,请确认已导出图元库!请确认已导出图元库!请确认已导出图元库!是否继续卸载?', mbConfirmation, MB_YESNO) = IDYES then beginResult:=true;end elseResult:=false;end;functionNeedInstallVC9SP1(): Boolean;beginResult :=vc9SP1Missing;end;functionNeedInstallVC9SP2(): Boolean;beginResult :=vc9SP2Missing;end;{实现水波纹效果} functionenablewater(ParentWnd: HWND; Left, Top: integer; Bmp: HBITMAP;
WaterRadius, WaterHeight: integer): BOOL; external
'enablewater@files:waterctrl.dll stdcall';//ParentWnd 放置特效窗口的父窗口句柄。//Left 左位置//Top 上位置//Bmp 位图句柄。//WaterRadius 水纹半径,会令到水纹看起来范围更广。//WaterHeight 水纹高度,会令到水纹看起来更深。//注意,水纹插件自动根据图片来设定高度和宽度,//另外水纹底图必须是翻转的图片,显示的时候会翻转图片来显示。function waterblob(x, y: integer; radius, height: integer): BOOL; external 'waterblob@files:waterctrl.dll stdcall';//在 x,y 点产生半径为radius, 高度为height 的水纹。function flattenwater(): BOOL; external 'flattenwater@files:waterctrl.dll stdcall';//平伏所有水纹。function disablewater(): BOOL; external 'disablewater@files:waterctrl.dll stdcall';//释放水纹插件function setwaterparent(ParentWnd: HWND): BOOL; external 'setwaterparent@files:waterctrl.dll stdcall';//v2 新增,设置水纹插件的父句柄varbmp: TBitmap;procedureInitializeWizard();varLabelDate: Tlabel;
uicmd: String;
beginExtractTemporaryFile('WizardImage.bmp');
bmp :
=TBitmap.create;
bmp.LoadFromFile(ExpandConstant(
'{tmp}\WizardImage.bmp'));

enablewater(WizardForm.WelcomePage.Handle,
0, 0, bmp.Handle, 3, 50);{欢迎页面添加文字}WizardForm.WelcomeLabel2.Autosize :=true;

LabelDate :
=Tlabel.Create(WizardForm);

LabelDate.Autosize :
=true;

LabelDate.Caption :
= '本程序由中望应用研发制作!'#10#13#10#13'了解更多ZWCAD信息请登录:https://www.zwcad.com/';if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{904DF7AD-D92A-4E81-A8ED-F0EB51701FFC}_is1', 'UninstallString', uicmd) then beginLabelDate.Font.Color := clred; //修改文字颜色
LabelDate.Caption :
= '检测到本机已安装其他版本,继续安装将会覆盖原版本!' #10#13#10#13'请确认已导出相关图元库!' end;


LabelDate.Parent :
=WizardForm.WelcomePage;

LabelDate.Left :
=WizardForm.WelcomeLabel2.Left;

LabelDate.Top :
= WizardForm.WelcomeLabel2.Top +WizardForm.WelcomeLabel2.Height +80;end;procedureCurPageChanged(CurPageID: Integer);begin if CurPageID = wpWelcome then beginsetwaterparent(WizardForm.WelcomePage.Handle);
waterblob(
70, 198, 10, 1000);end else if CurPageID = wpFinished then beginsetwaterparent(WizardForm.FinishedPage.Handle);
waterblob(
70, 198, 10, 1000);end elseflattenwater();end;procedureDeinitializeSetup();begindisablewater();
bmp.Free;
end;


————————————————
版权声明:本文为CSDN博主「wang161019」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wang161019/article/details/91491300