當前位置:首頁 » 編程語言 » C語言VMProtect殼
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

C語言VMProtect殼

發布時間: 2022-12-29 09:11:06

① 如何用c語言對文件進行加密和解密急求......................

文件分為文本文件和二進制文件。加密方法也略有不同。
1、文本文件
加密的主要是文本的內容,最簡單的方法就是修改文檔的內容,比如1.txt中的文件內容:
abcd
只要給每一個字元+1,就可以實現加密。文件內容即會變為
bcde

2、二進制文件加密
二進制文件加密也就是對應用程序加密,需要理解可執行文件格式,比如Windows平台的Exe文件它是PE結構,Linux上的可執行文件是ELF結構,要對這樣的程序進行加密,實際上是開發一種叫做「殼」的程序,這種程序的開發,需要將扎實的底層基礎,同時也需要對軟體加密解密有細致的理解,比如流行的vmprotect、z殼以及早些年的upx殼、aspack等等。

3、無論哪種加密都牽涉到文件操作的問題,使用C語言進行文件操作時,極少使用C標准庫中的I/O函數,大多數使用操作系統提供的內存文件映射相關的API函數,有興趣,可以搜索相關的資料。

② c語言 模塊化編程 MAIN.C(28): error C141: syntax error near 'void'

你把main(void)中的那個void刪了試試,學過很久了,軟體也卸了,沒辦法幫你運行,但是我記得C語言中不支持這樣的寫法,你試試看。如果不對再幫你解答。

③ C語言中Cannot open include file: 'R.h': No such file or directory怎麼解決 以及PROTECT()有什麼作用

你引用了R.h庫函數,而你電腦沒有這個庫函數,你可以刪掉試一下

④ c語言中 #include<windos.h>文件頭除了能限制機器輸出時間,還有什麼用途

是windows.h吧。這個頭文件里有好多函數。你確定你都想知道么。
下面就是啦:
有關進程系統許可權類
1:函數OpenProcessToken(
HANDLE ProcessHandle,//進程的句柄
DWORD DesiredAccess,//對進程的訪問描述
PHANDLE TokenHandle//打開進程令牌的句柄指針
);
這個函數的作用是打開進程令牌
2: 函數LookupPrivilegeValue(
LPCTSTR lpSytemName,//系統名稱
LPCTSTR lpName,//特權名稱
PLUID lpluid//本地系統唯一的ID號
)
這個函數將返回一個本地系統內獨一無二的ID,來用於系統許可權的更改,它的第一個參數是系統名,nil表示本系統。第2個參數是特權的名字。第3個參數用來接收函數返回的ID。
3.函數AdjustTokenPrivileges(
HANDLE TokenHandle, //更改許可權的令牌環句柄
BOOL DisableAllPrivileges, //是否修改所有許可權的標志位
PTOKEN_PRIVILEGES NewState, //新的系統許可權信息
DWORD BufferLength, //上一個參數的長度
PTOKEN_PRIVILEGES PreviousState, // 返回更改系統特權以前的許可權
PDWORD ReturnLength //上一個參數的長度
);
這個函數用於更改進程的系統許可權 ,第1個參數是要更改許可權的令牌環句柄。第2個參數如果為true表示更改所有的系統許可權 ,false表示更改部分。第3個參數是要更改的系統特權的值。第4個參數是第3個參數的大小。第5個參數返回更改系統特權以前的許可權,我們不需要就設為nil。第6個參數是第5個參數的大小。

OpenProcess(
DWORD dwDesiredAccess,//訪問標志
BOOL bInheritHandle,//繼承句柄標志
DWORD dwProcessId //進程Id
)
這個函數用於修改我們宿主進程的一些屬性,這些屬性放在第一個參數裡面比如說PROCESS_VM_OPEARTION就是允許遠程VM操作,即允許VirtualProtectEx和WriteProcessMemory函數操作本進程內存空間。PROCESS_VM_WRITE就是允許遠程VM寫,即允許WriteProcessMemory函數訪問本進程的內存空間。第二個參數是一個標志參數,用來確定返回的句柄是否可以被新的進程繼承。我們的程序中設為False。第三個參數需要操作的進程Id,也就是我們的宿主進程的ID。
2:函數VirtualAllocEx(
HANDLE hProcess,//要進行操作的進程句柄,當然是我們的宿主了
LPVOID lpAddress,//分配空間的開始地址
DWORD dwSize,//分配空間的大小
DWORD flAllocationType,//分配空間的類型
DWOrd flProtect//訪問保護類型

我們使用VirtualAllocEx函數在宿主進程中開辟一塊內存空間,用於存放dll的文件名,VirtualAllocEx的第一參數是要操作的進程,第二個是開始地址,第三個是長度,第4,5個是操作參數。其中MEM_COMMIT表示本函數分配的物理內存或者是內存的頁面文件,PAGE_READWRITE表示分配的區域內允許讀寫
函數WriteProcessMemory(
HANDLE hProcess,//所要操作的線程的句柄
LPVOID lpBaseAddress,//開始進行操作的起始地址
LPVOID lpBuffer,//所要寫入的Bytes數
LPDWORD lpNuberofBytersWriteen//世紀寫入的Bytes數

) 前面的函數在宿主內存中創建號空間後,現在往裡面寫入dll的名稱,而我們的WriteProcessMemory函數就可以勝任這一項工作,WriteProcessMemory函數的第一個參數是需要往內存裡面寫入dd的進程句柄,第二個參數是 「要進行寫操作」的目標內存起始地址,第三個參數是 「需要被寫入的數據」的地址,第四個參數是准備要寫入的長度,第五個參數是實際操作中寫的長度,這個參數是被函數輸出的。到這里我們就已經能成功把dll的路徑名稱寫進了宿主的內存空間。
GetProcAddress(
HMODULE hMole, //dll模塊的句柄
LPCSTR lpProcName // 函數名稱
);
我們用這個函數主要想得到kernel32.dll中的函數LoadLibraryW的入口地址,所以
GetProcAddress(GetMoleHandle('Kernel32'), 'LoadLibraryW')就可以了,當然有些細節得符合程序編譯器的要求,VC下使用就要改成
GetProcAddress(GetMoleHandle(TEXT("Kernel32")), "LoadLibraryW")的形式。

CreateRemoteThread (
HANDLE hProcess, //要進行操作的進程句柄,也就是我們的宿主句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes, //線程安全屬性的指針
DWORD dwStackSize, //初始化堆(stack)的大小
LPTHREAD_START_ROUTINE lpStartAddress,//新建線程函數的指針,或叫做地址
LPVOID lpParameter, //新建線程函數的參數
DWORD dwCreationFlags, //標志位
LPDWORD lpThreadId //線程返回值
);
這個函數就是本文的點睛之筆了,我們之前所做所有的一切,都是在為它做准備工作,它的功能就是在其他任何進程中創建新的線程,讓其他的程序或進程附加執行我們的代碼。
CreateRemoteThread函數的第一個參數是要操作的宿主進程句柄;第二個參數為線程安全參數的指針,這里設為nil;第三個參數為初始化堆(stack)的大小,這里設0;第四個參數為新建線程函數的指針或叫做地址或叫入口;第五個參數為新建線程函數的參數,這里就是我們的dll路徑名稱;第六個參數是標志位,這里設0;第七個參數是線程返回值。

⑤ c語言中的繼承用什麼關鍵字

在C語言中,不存在繼承的概念。

繼承是面向對象語言的概念,而C語言是面向過程的語言。
C++是在C語言基礎上發展出的面向對象語言,其中的類可以繼承。
在C++的繼承中,區分繼承類型,有三種關鍵字可以使用:
1 公有繼承,使用關鍵字public;
2 私有繼承,使用關鍵字private;
3 保護繼承,使用關鍵字protect。

⑥ 免殺的方法

一.入口點加1免殺法:

1.用到工具PEditor
2.特點:非常簡單實用,但有時還會被卡巴查殺]
3.操作要點:用PEditor打開無殼木馬程序,把原入口點加1即可

【二.變化入口地址免殺法:】

1.用到工具:OllyDbg,PEditor
2.特點:操作也比較容易,而且免殺效果比入口點加1點要佳.
3.操作要點:用OD載入無殼的木馬程序,把入口點的前二句移到零區域去執行,然後
又跳回到入口點的下面第三句繼續執行.最後用PEditor把入口點改成零區域的地址

【三.加花指令法免殺法:】

1.用到工具:OllyDbg,PEditor
2.特點:免殺通用性非常好,加了花指令後,就基本達到大量殺毒軟體的免殺.
3.操作要點:用OD打開無殼的木馬程序,找到零區域,把我們准備好的花指令填進去
填好後又跳回到入口點,保存好後,再用PEditor把入口點改成零區域處填入花指令的著地址.

【四.加殼或加偽裝殼免殺法:】

1.用到工具:一些冷門殼,或加偽裝殼的工具,比如木馬綵衣等.
2.特點:操作簡單化,但免殺的時間不長,可能很快被殺,也很難躲過卡巴的追殺
3.操作要點:為了達到更好的免殺效果可採用多重加殼,或加了殼後在加偽裝殼的免殺效果更佳

【五.打亂殼的頭文件或殼中加花免殺法:】

1.用到工具:秘密行動 ,UPX加殼工具.
2.特點:操作也是傻瓜化,免殺效果也正當不錯,特別對卡巴的免殺效果非常好
3.操作要點:首先一定要把沒加過殼的木馬程序用UPX加層殼,然後用秘密行動這款
工具中的SCramble功能進行把UPX殼的頭文件打亂,從而達到免殺效果.

【六.修改文件特徵碼免殺法:】

1.用到工具:特徵碼定位器,OllyDbg
2.特點:操作較復雜,要定位修改一系列過程,而且只針對每種殺毒軟體的免殺,要達
到多種殺毒軟體的免殺,必需修改各種殺毒軟體的特徵碼.但免殺效果好

[特徵碼修改方法]

特徵碼修改包括文件特徵碼修改和內存特徵碼修改,因為這二種特徵碼的修改方
法是通用的。所以就對目前流行的特徵碼修改方法作個總節。

[方法一:直接修改特徵碼的十六進製法]
1.修改方法:把特徵碼所對應的十六進制改成數字差1或差不多的十六進制.
2.適用范圍:一定要精確定位特徵碼所對應的十六進制,修改後一定要測試一下能否正常使用.

[方法二:修改字元串大小寫法]
1.修改方法:把特徵碼所對應的內容是字元串的,只要把大小字互換一下就可以了.
2.適用范圍:特徵碼所對應的內容必需是字元串,否則不能成功.

[方法三:等價替換法]
1.修改方法:把特徵碼所對應的匯編指令命令中替換成功能類擬的指令.
2.適用范圍:特徵碼中必需有可以替換的匯編指令.比如JN,JNE 換成JMP等.如果和我一樣對匯編不懂的可以去查查8080匯編手冊.

[方法四:指令順序調換法]
1.修改方法:把具有特徵碼的代碼順序互換一下.
2.適用范圍:具有一定的局限性,代碼互換後要不能影響程序的正常執行

[方法五:通用跳轉法]
1.修改方法:把特徵碼移到零區域(指代碼的空隙處),然後一個JMP又跳回來執行.
2.適用范圍:沒有什麼條件,是通用的改法,強烈建議大家要掌握這種改法.

木馬免殺的綜合修改方法

文件免殺方法:1.加冷門殼 2.加花指令 3.改程序入口點 4.改木馬文件特徵碼的5種常用方法
5.還有其它的幾種免殺修改技巧

【七.內存免殺方法:】

修改內存特徵碼:
方法1>直接修改特徵碼的十六進製法
方法2>修改字元串大小寫法
方法3>等價替換法
方法4>指令順序調換法
方法5>通用跳轉法

殼入口修改法
1.用到工具:壓縮殼 OD
2.特點:操作簡單 免殺效果好
3.操作步驟:首先給木馬加壓縮殼 然後用OD載入,在入口處的前15句中NOP掉某些代碼或者等價代換某些代碼

【八.輸入表免殺方法:】

[一,移位法]

1 首先用lordpe打開,目錄,導入表找到你要改的函數。比如說CommandLineA
2 記下未改前函數的thunkvalue 舉例:00062922
3 將要修改的文件用winhex等16進制形式打開,然後找到該函數的地址,比如說00062988
4 將該函數用00填充,移動到新地址如00070000
5 保存
6 將保存後的文件用lordpe打開,打開計算器,選擇16進制,00062988-00062922+00070000,計算結果修改為新的thunkvalue。保存
註:公式-> 內存地址=RAV+RAV基址 ,RAV基地址可以在LORDPE中看到.輸入表函數名前有兩個空格所以RAV的地址要減去2

[二,修改字元法]

今天定位Drat2.9卡巴特徵碼,是在輸入表上!(這時句廢話,現在卡巴基本都殺輸入表)

[特徵] 00025175_00000001 ZwUnmapViewOfSection 他的特徵碼位置是函數後面的那個00

(這個函數我在開始移動過位置,原始DAT文件的特徵碼是0002516A_00000001,同樣是函數後面的那個00)
我開始是選擇C32移動位置,LordPE修改輸入表,但是不行,後來試過OD指針移位,還是不行!CALL改JMP都不行
我發現LordPE可以修改函數名稱!便用C32將ZwUnmapViewOfSection函數後面加了個字元b(你可以隨意加字元)

由於LordPE讀取輸入表函數是從ThunkValue開始,一直到這個連續的字元串後的00處!
由於在ZwUnmapViewOfSection函數後加了個字元b,現在LordPE讀取的此處函數為ZwUnmapViewOfSectionb

此時將ZwUnmapViewOfSectionb函數後面的那個b刪除!保存下文件,這時就免殺了!

這樣一修改,在文件00025175處的16進制代碼不是00,而是62,所以卡巴就過了,而用lardPE修改後函數後,文件的輸入表的函數還是ZwUnmapViewOfSection,生成服務端可以運行!

【免殺經驗:】

1.加區,加花後,再加密,可以比較容易過卡巴----如加密工具vmprotect

脫殼過的木馬---加花指令,或加區加花---加密---加壓縮殼---再加區加花指令

2.單單加免殺花指令已經不能過卡巴,一定要配合加花後在加壓縮殼,才能起到免殺卡巴的效果.

vmprotect加密----再加花-----可過卡巴:

3.加雙層花指令免殺法----免卡巴

4.加密---007內存免----加壓 ---免卡巴或內存.

5.雙層加密(maskpE)---加壓 ----可過卡巴.

6.maskpe加密---asppack加殼 ---改入口點加1---可過卡巴

7.加密maskpe----加花或加區加花(用工具)-----加壓縮殼---免卡巴

8.北斗對黑防鴿子可加壓二次,再壓其它壓縮殼.以達免殺.

9.加過北斗殼,向上拉滾開滑鼠50多次,有一段空代碼,可以加花,轉移.

10.去頭轉移入口點---加花----加密(vmprotect) ----加壓縮==過所有殺毒

11.對付卡巴,加免殺花指令.花指令對瑞星表面查殺一般無效,一般加壓縮殼.

12.對付瑞星表面: 有些黑軟,加區,加花後被瑞星表面殺,可以這樣:先加壓過瑞星表面,然後加免殺花指令,過卡巴.

13.過瑞星表面的查殺方法: 1.加北斗內存免殺壓縮殼 2.加過瑞星表面的專用加密工具. 3.用maskPE加密工具加密 源碼免殺,要求樓主必須會編程語言,如C語言,E語言等。可以載入IDA中調試,通過修改源碼語句。

⑦ C語言 如何讓任務管理器無法結束進程

HOOK TerminateProcess()這個API函數

我這里有源代碼,要的話留郵箱

我先把主要的自定義類貼出來:

/////////////////////////////////////////////////////////
// APIHook.h文件

#ifndef __APIHOOK_H__
#define __APIHOOK_H__

#include <windows.h>

class CAPIHook
{
public:
CAPIHook(LPSTR pszModName,
LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod = TRUE);
virtual ~CAPIHook();
operator PROC() { return m_pfnOrig; }

// 實現
private:
LPSTR m_pszModName; // 導出要HOOK函數的模塊的名字
LPSTR m_pszFuncName; // 要HOOK的函數的名字
PROC m_pfnOrig; // 原API函數地址
PROC m_pfnHook; // HOOK後函數的地址
BOOL m_bExcludeAPIHookMod; // 是否將HOOK API的模塊排除在外

private:
static void ReplaceIATEntryInAllMods(LPSTR pszExportMod, PROC pfnCurrent,
PROC pfnNew, BOOL bExcludeAPIHookMod);
static void ReplaceIATEntryInOneMod(LPSTR pszExportMod,
PROC pfnCurrent, PROC pfnNew, HMODULE hModCaller);

// 下面的代碼用來解決其它模塊動態載入DLL的問題
private:
// 這兩個指針用來將所有的CAPIHook對象連在一起
static CAPIHook *sm_pHeader;
CAPIHook *m_pNext;

private:
// 當一個新的DLL被載入時,調用此函數
static void WINAPI HookNewlyLoadedMole(HMODULE hMole, DWORD dwFlags);

// 用來跟蹤當前進程載入新的DLL
static HMODULE WINAPI LoadLibraryA(PCSTR pszMolePath);
static HMODULE WINAPI LoadLibraryW(PCWSTR pszMolePath);
static HMODULE WINAPI LoadLibraryExA(PCSTR pszMolePath, HANDLE hFile, DWORD dwFlags);
static HMODULE WINAPI LoadLibraryExW(PCWSTR pszMolePath, HANDLE hFile, DWORD dwFlags);

// 如果請求已HOOK的API函數,則返回用戶自定義函數的地址
static FARPROC WINAPI GetProcAddress(HMODULE hMole, PCSTR pszProcName);
private:
// 自動對這些函數進行掛鉤
static CAPIHook sm_LoadLibraryA;
static CAPIHook sm_LoadLibraryW;
static CAPIHook sm_LoadLibraryExA;
static CAPIHook sm_LoadLibraryExW;
static CAPIHook sm_GetProcAddress;
};

#endif // __APIHOOK_H__

//////////////////////////////////////////////////////////////
// APIHook.cpp文件

#include "APIHook.h"
#include "Tlhelp32.h"

#include <ImageHlp.h> // 為了調用ImageDirectoryEntryToData函數
#pragma comment(lib, "ImageHlp")

// CAPIHook對象鏈表的頭指針
CAPIHook* CAPIHook::sm_pHeader = NULL;

CAPIHook::CAPIHook(LPSTR pszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod)
{
// 保存這個Hook函數的信息
m_bExcludeAPIHookMod = bExcludeAPIHookMod;
m_pszModName = pszModName;
m_pszFuncName = pszFuncName;
m_pfnHook = pfnHook;
m_pfnOrig = ::GetProcAddress(::GetMoleHandle(pszModName), pszFuncName);

// 將此對象添加到鏈表中
m_pNext = sm_pHeader;
sm_pHeader = this;

// 在所有當前已載入的模塊中HOOK這個函數
ReplaceIATEntryInAllMods(m_pszModName, m_pfnOrig, m_pfnHook, bExcludeAPIHookMod);
}

CAPIHook::~CAPIHook()
{
// 取消對所有模塊中函數的HOOK
ReplaceIATEntryInAllMods(m_pszModName, m_pfnHook, m_pfnOrig, m_bExcludeAPIHookMod);

CAPIHook *p = sm_pHeader;

// 從鏈表中移除此對象
if(p == this)
{
sm_pHeader = p->m_pNext;
}
else
{
while(p != NULL)
{
if(p->m_pNext == this)
{
p->m_pNext = this->m_pNext;
break;
}
p = p->m_pNext;
}
}

}

void CAPIHook::ReplaceIATEntryInOneMod(LPSTR pszExportMod,
PROC pfnCurrent, PROC pfnNew, HMODULE hModCaller)
{
// 取得模塊的導入表(import descriptor)首地址。ImageDirectoryEntryToData函數可以直接返回導入表地址
ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
::ImageDirectoryEntryToData(hModCaller, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
if(pImportDesc == NULL) // 這個模塊沒有導入節表
{
return;
}

// 查找包含pszExportMod模塊中函數導入信息的導入表項
while(pImportDesc->Name != 0)
{
LPSTR pszMod = (LPSTR)((DWORD)hModCaller + pImportDesc->Name);
if(lstrcmpiA(pszMod, pszExportMod) == 0) // 找到
break;

pImportDesc++;
}
if(pImportDesc->Name == 0) // hModCaller模塊沒有從pszExportMod模塊導入任何函數
{
return;
}

// 取得調用者的導入地址表(import address table, IAT)
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(pImportDesc->FirstThunk + (DWORD)hModCaller);

// 查找我們要HOOK的函數,將它的地址用新函數的地址替換掉
while(pThunk->u1.Function)
{
// lpAddr指向的內存保存了函數的地址
PDWORD lpAddr = (PDWORD)&(pThunk->u1.Function);
if(*lpAddr == (DWORD)pfnCurrent)
{
// 修改頁的保護屬性
DWORD dwOldProtect;
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery(lpAddr, &mbi, sizeof(mbi));
::VirtualProtect(lpAddr, sizeof(DWORD), PAGE_READWRITE, &dwOldProtect);

// 修改內存地址 相當於「*lpAddr = (DWORD)pfnNew;」
::WriteProcessMemory(::GetCurrentProcess(),
lpAddr, &pfnNew, sizeof(DWORD), NULL);

::VirtualProtect(lpAddr, sizeof(DWORD), dwOldProtect, 0);
break;
}
pThunk++;
}
}

void CAPIHook::ReplaceIATEntryInAllMods(LPSTR pszExportMod,
PROC pfnCurrent, PROC pfnNew, BOOL bExcludeAPIHookMod)
{
// 取得當前模塊的句柄
HMODULE hModThis = NULL;
if(bExcludeAPIHookMod)
{
MEMORY_BASIC_INFORMATION mbi;
if(::VirtualQuery(ReplaceIATEntryInAllMods, &mbi, sizeof(mbi)) != 0)
hModThis = (HMODULE)mbi.AllocationBase;
}

// 取得本進程的模塊列表
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ::GetCurrentProcessId());

// 遍歷所有模塊,分別對它們調用ReplaceIATEntryInOneMod函數,修改導入地址表
MODULEENTRY32 me = { sizeof(MODULEENTRY32) };
BOOL bOK = ::Mole32First(hSnap, &me);
while(bOK)
{
// 注意:我們不HOOK當前模塊的函數
if(me.hMole != hModThis)
ReplaceIATEntryInOneMod(pszExportMod, pfnCurrent, pfnNew, me.hMole);

bOK = ::Mole32Next(hSnap, &me);
}
::CloseHandle(hSnap);
}

// 掛鉤LoadLibrary和GetProcAddress函數,以便在這些函數被調用以後,掛鉤的函數也能夠被正確的處理

CAPIHook CAPIHook::sm_LoadLibraryA("Kernel32.dll", "LoadLibraryA",
(PROC)CAPIHook::LoadLibraryA, TRUE);

CAPIHook CAPIHook::sm_LoadLibraryW("Kernel32.dll", "LoadLibraryW",
(PROC)CAPIHook::LoadLibraryW, TRUE);

CAPIHook CAPIHook::sm_LoadLibraryExA("Kernel32.dll", "LoadLibraryExA",
(PROC)CAPIHook::LoadLibraryExA, TRUE);

CAPIHook CAPIHook::sm_LoadLibraryExW("Kernel32.dll", "LoadLibraryExW",
(PROC)CAPIHook::LoadLibraryExW, TRUE);

CAPIHook CAPIHook::sm_GetProcAddress("Kernel32.dll", "GetProcAddress",
(PROC)CAPIHook::GetProcAddress, TRUE);

void WINAPI CAPIHook::HookNewlyLoadedMole(HMODULE hMole, DWORD dwFlags)
{
// 如果一個新的模塊被載入,掛鉤各CAPIHook對象要求的API函數
if((hMole != NULL) && ((dwFlags&LOAD_LIBRARY_AS_DATAFILE) == 0))
{
CAPIHook *p = sm_pHeader;
while(p != NULL)
{
ReplaceIATEntryInOneMod(p->m_pszModName, p->m_pfnOrig, p->m_pfnHook, hMole);
p = p->m_pNext;
}
}
}

HMODULE WINAPI CAPIHook::LoadLibraryA(PCSTR pszMolePath)
{
HMODULE hMole = ::LoadLibraryA(pszMolePath);
HookNewlyLoadedMole(hMole, 0);
return(hMole);
}

HMODULE WINAPI CAPIHook::LoadLibraryW(PCWSTR pszMolePath)
{
HMODULE hMole = ::LoadLibraryW(pszMolePath);
HookNewlyLoadedMole(hMole, 0);
return(hMole);
}

HMODULE WINAPI CAPIHook::LoadLibraryExA(PCSTR pszMolePath, HANDLE hFile, DWORD dwFlags)
{
HMODULE hMole = ::LoadLibraryExA(pszMolePath, hFile, dwFlags);
HookNewlyLoadedMole(hMole, dwFlags);
return(hMole);
}

HMODULE WINAPI CAPIHook::LoadLibraryExW(PCWSTR pszMolePath, HANDLE hFile, DWORD dwFlags)
{
HMODULE hMole = ::LoadLibraryExW(pszMolePath, hFile, dwFlags);
HookNewlyLoadedMole(hMole, dwFlags);
return(hMole);
}

FARPROC WINAPI CAPIHook::GetProcAddress(HMODULE hMole, PCSTR pszProcName)
{
// 得到這個函數的真實地址
FARPROC pfn = ::GetProcAddress(hMole, pszProcName);

// 看它是不是我們要hook的函數
CAPIHook *p = sm_pHeader;
while(p != NULL)
{
if(p->m_pfnOrig == pfn)
{
pfn = p->m_pfnHook;
break;
}

p = p->m_pNext;
}

return pfn;
}

如果你對HOOK API有一頂的了解m就可以用這個類來實現你的程序:

最重要的2個介面:

static void ReplaceIATEntryInAllMods(LPSTR pszExportMod, PROC pfnCurrent,
PROC pfnNew, BOOL bExcludeAPIHookMod);

HOOK所有模塊

static void ReplaceIATEntryInOneMod(LPSTR pszExportMod,
PROC pfnCurrent, PROC pfnNew, HMODULE hModCaller);
HOOK 指定模塊

你只要能使所有進程都HOOK所有模塊,就能達到你的目的

<很明顯利用全局鉤子嘛>

把你要HOOK的代碼放到DLL裡面,讓所有進程載入,就能實現了

⑧ 用軟體做免殺改特徵碼的方法

一、主動免殺1. 修改字元特徵:主動查找可能的特徵碼,包括木馬文件修改注冊表、生成新文件的名稱與路徑、注入的進程名等動作,也包括運行過程中可能出現或一定會出現的字元等文件特徵。然後找出這些字元,並將其修改。2. 修改輸入表:查找此文件的輸入表函數名(API Name),並將其移位。3. 打亂文件結構:利用跳轉(JMP),打亂文件原有結構。4. 修改入口點:將文件的入口點加1。5. 修改PE段:將PE段移動到空白位置二、被動免殺1. 修改特徵碼:用一些工具找出特徵碼並針對特徵碼做免殺處理。2. 用Vmprotect:使用Vmprotect加密區段。3. 文件加殼:可以用一些比較生僻的殼對木馬文件進行保護。有的朋友看到這里有可能蒙了,PE、Vmprotect、入口點……這些都是什麼意思啊?不要著急,下面我會一一介紹的,只要你看完這篇文章,就一定會成為免殺高手!怎麼樣?Go!3.實戰演習1.)修改字元特徵好,下面我們依然以一個病毒防禦工作者的角度來考慮我們每一步應該做什麼,然後在利用逆向思維分而治之。現在假如我們拿到一個木馬樣本灰鴿子,首先當然要分析它究竟有什麼功能,怎樣運行以及怎樣保護自己等。其實這一步要求的專業知識是很多的,但考慮到我們的讀者,我們暫且用一個比較簡單易行的方法——運行木馬AND查看此程序的幫助文檔。我們打開RegSnap,新建一個快照,打開RegSnap後,點擊[新建快照]按鈕(如圖1)。
在彈出的對話框中選擇[生成所有項目的快照](如圖2)。然後保存快照,現在已經將RegSnap配置好了,下面運行我們的木馬程序(提醒:做免殺時,一定要記住養好隨時備分的好習慣,以防止修改錯誤或是實驗運行時破壞、刪除木馬)。木馬運行完畢後,我們在按照上面的方法重新做一個快照並保存,然後按快捷鍵F5,在彈出的「比較快照」對話框中選擇剛才保存的快照,在「第一個快照」中選擇我們剛才第一次保存的快照,而「第二個快照」選擇我們後保存的快照存檔,很快結果就出來了(如圖3)。
有的朋友對於使用RegSnap收集到的信息感到無力分析,抱怨收集到的東西太多,在這里我簡單的介紹一下,首先應注意的是生成做對比的兩個快照之間的時間要盡可能短,另外要排除帶有OpenSaveMRU的注冊表鍵值,還要排除有關*.rsnp文件的創建讀寫等操作記錄。下面我們就將有用的信息提取出來,逐一分析。文件列表於 C:\WINDOWS\*.*新增文件木馬.exe注冊表報告新增主鍵HKEY_CURRENT_USER\Software\Microsoft\Windows\ShellNoRoam\MUICache\C:\Documents and Settings\A1Pass-admin\桌面\huigezi\復件 Server02.exe鍵值: 字元串: "復件 Server02"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_*6728*9A6C*670D*52A1\0000\Class鍵值: 字元串: "LegacyDriver"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_*6728*9A6C*670D*52A1\0000\ClassGUID鍵值: 字元串: "{8ECC055D-047F-11D1-A537-0000F8753ED1}"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\Root\LEGACY_*6728*9A6C*670D*52A1\0000\Control\ActiveService鍵值: 字元串: "木馬服務"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\木馬服務\Description鍵值: 字元串: "灰鴿子服務端程序。遠程監控管理."……這里我只摘錄了部分關鍵性的木馬動作記錄,全部記錄請見光碟。通過文件列表我們可以知道木馬在WINDOW目錄下生成了一個新文件,而通過注冊表的監控信息我們也知道了木馬是怎樣將自己注冊為系統服務並自動運行的。那麼我們回到瑞星的研究分析室,看看那些大哥大姐們會怎麼辦……瑞星大哥:「最近這灰鴿子太猖狂啦!我們是不是應該多定義幾套特徵碼?」瑞星大姐:「恩,不錯!先在注冊表那定義一套特徵碼在說吧。」A1Pass:「STOP!!」(只見畫面突然定格,A1Pass將播放器最小化。)通過上面的對話,我們可以知道他們要將注冊表的某個字元定義為特徵碼,從上面RegSnap分析出來的記錄來看,他們的選擇真的是太多了!那麼他們究竟會用到哪些呢?其實,就做為一個黑客來講,只要不影響服務端正常運行,就應該盡量多的改掉木馬的所有字元,當然全部改變是不可能的,除非你自己編寫木馬。有的朋友要問了,除了注冊表別的就不可以改了嗎?答案當然是否定的,譬如生成新文件的名稱與路徑、注入的進程名等動作,這些我們可以利用WINDOWS對字母大小寫不敏感的這一特點直接替換字母的大小寫,而對於運行過程中可能出現或一定會出現的字元等我們可以直接將其替換成別的內容。下面我為大家演示一下怎樣更改注入進程的名稱。首先配置服務端,通過圖4我們可以看出來灰鴿子的啟動運行是需要「IEXPLORE.EXE」這個進程的,根據注冊表的推理,我們可以認為其未加殼的服務端是應該存在「IEXPLORE.EXE」這一字元串的。既然如此,我們就先請出我們的第一把武器「WinHex」!
WinHex是一款極為出名16進制編輯器。得到 ZDNetSoftwareLibrary 五星級最高評價,擁有強大的系統效用。在這里,我們只用它來編輯文件,其餘不做過多討論。首先我們用WinHex打開我們的木馬文件「Server.exe」,打開後如圖5所示。
然後我們按[Ctrl]+[F]快捷鍵調出查找文本對話框,輸入IEXPLORE.EXE後點擊「是」(如圖6)。
結果如圖7所示。下面我們就對其進行大小寫轉換,用滑鼠點擊要更改的字母(例如I),然後在按鍵盤上的i,即可完成更改,就象使用WINDOWS的記事本一樣。更改完畢後,按[Ctrl]+[S]快捷鍵保存即可。
就這么簡單?對!就這么簡單!其他的例如注冊表、生成新文件的名稱與路徑等等都可以利用此方法更改。但是不幸的是,經過這樣改後,還不足以對付例如金山、江民等品牌殺毒軟體,要想對付這些殺毒軟體的查殺,我們還需要對我們的木馬進行進一步處理。下面,我們開始學習輸入表函數(APIName)免殺!2.)修改輸入表不知有的朋友是否知道,PE文件的正常運行是離不開其內部輸入表函數的,而不同的程序,其內部輸入表函數的名稱與在文件中的位置是不一樣的,所以輸入表函數也成了病毒防禦工作者製作特徵碼緊盯的地方之一。在我查出來的關於灰鴿子的特徵碼來看,「瑞星大哥」已經將其的一處輸入表函數作為特徵碼了。所以掌握輸入表函數免殺技巧對於新入門的朋友來說勢在必行!
[PE文件小知識:PE文件是WINDOWS系統中特有的一種文件結構,它包括PE文件頭、輸入表與相關資源文件等等]經過我的測試,直接單獨修改文件內部的輸入表函數會導致程序運行不正常甚至崩潰!那就沒有辦法了嗎?我可沒那麼容易認輸!經過一翻苦戰,終於讓我在LordPE中找到了解決辦法,同時FoBnN的文章也給了我非常大的啟發……我們先打開LordPE,點擊[PE編輯器]按鈕,在彈出的對話框中選中木馬文件,打開後點擊[目錄](如圖8)。在點擊導入表後面的[…](如圖9)。在彈出的對話框中我們選擇wininet.dll下的InternetOpenUrlA(如圖10),有的朋友要問了,為什麼非選擇InternetOpenUrlA這個輸入表函數呢?呵呵!那是因為這個輸入表裡有特徵碼哦,關於怎樣確定特徵碼,我在後面會介紹,大家先別著急。
好的,關於LordPE就先停在這,下面我們就用WinHex來查找InternetOpenUrlA這個輸入表函數的所在位置,並將其用0填充(操作方法:單擊WinHex右面的16進制信息,輸入0即可)(如圖11、12)。
然後將其寫到空白區域(既顯示000000的區域),一定要從頭開始寫入,這樣在以後計算地址時不容易出錯,除此之外也要注意輸入表函數的大小寫不要搞錯(如圖13)。保存後我們在回到LordPE那裡,在需要更改的InternetOpenUrlA輸入表函數上單擊右鍵,在彈出的菜單里選擇「編輯」,將Thunk里的信息改成000B9D5E(如圖14)即可。有的朋友要問了,剛才我們不是把那個輸入表函數放到000B9D60那裡了嗎?到這怎麼變成000B9D5E了?其實原理很簡單,因為每個輸入表函數前面都是有一個空格的,我們雖不用真正把那個空格加進去,但填寫它的地址時一定要空出來,否則就會出錯!而將000B9D60減去一個空格所佔的位置,其地址正好為000B9D5E,還不十分明白的朋友在仔細看看圖13,下面我們在回到LordPE,看看我們改過的輸入表函數變成什麼樣了(如圖15)?呵呵!那我們該怎麼辦呢?其實簡單的很,只要在重新改一下輸入表函數的名稱就可以了(如圖16)。有的時候因為我們所填寫的地址為比較靠後的,例如我們現在改的這個000B9D5E,後面僅能容納兩個位元組,所以更改輸入表函數時只能鍵入兩個字,對於這種情況我們可以先把Thunk里的信息改成如000B9D60這樣的起始地址,改輸入表函數名更改完畢後在將000B9D60改回原來的值(既000B9D5E),保存後即可成功,我們試一下看看(如圖17)。經測驗鴿子的各項功能均正常!在用瑞星查一下試試(如圖18),結果當然不言而喻……
3.)修改特徵碼雖然到這我們免殺已經成功,但是為了學到更多的技術,為了讓我們免殺的鴿子存活的更久,下面我在為大家介紹一下特徵碼的查找與修改技巧。特徵碼是殺毒軟體的心臟,但同樣也是我們的心臟!就看誰先找到對方地心臟,並能發出致命一擊,誰就是勝利者!一提到查找特徵碼,就不得不說說MyCCL與CCL,這兩個軟體的名字相信留心過免殺技術的朋友不會陌生,但由於軟體操作的傻瓜化,很多時候對於CCL的介紹只是一帶而過,這可苦了入門的朋友!這一小節我就先介紹一下MyCCL的用法……我們先來認識一下MyCCL(如圖19),根據這張圖我們下面就來大體介紹一下MyCCL的應用方法。首先點擊第1處選擇文件,然後在第2處輸入分塊個數,分塊個數越多,定位越精確,然而生成的速度同時也就越慢,生成的文件總體積也就越大,就象灰鴿子這么大的服務端,如果分塊數為300的話,那麼它生成文件的總體積將超過230M!所以在這里不建議填寫太大的數字,一般象灰鴿子這樣的服務端分塊數填400個就足夠了。生成完畢後會彈出個對話框提醒你去相應目錄殺毒,圖中所示為「E:\文章\極度免殺\鴿子\OUTPUT」文件夾,我們到那個文件夾下開始殺毒,查到病毒就讓殺毒軟體將其徹底刪除,注意,這一點很重要!處理完畢後點擊第3處的二次處理,在點擊[生成]上面的[特徵區間]按鈕即可出現右面的對話框。下面我們在「區間設定」里右鍵單擊特徵碼區間,在彈出的菜單中選擇「復合精確定位此處特徵」(如圖20),然後重復上面的操作,直到你認為[單位長度]已經小到很方便更改的時候,特徵碼的定位就算結束了。好了,一口氣說了這么多,不知道剛入門的朋友是否懂得一些MyCCL的用法了沒有……但是上面我們定位的是文件特徵碼,還有內存特徵碼沒有定義,這里我們要用到CCL的內存特徵碼定位功能,打開CCL後,我們依次選擇[文件]→[特徵碼驗測]→[內存特徵碼](如圖21)。
在彈出的對話框中選擇我們要進行免殺操作的木馬,然後會進入「定位范圍選擇窗口」(如圖22)。由圖中可知,第一個CODE段的偏移量為00000400,也就是說我們可以用00000400做為起始位置,那麼我么就在用戶輸入區的「起始位置」處填寫00000400,下面的那個驗測大小怎麼填寫呢?看到圖22中畫線的那個「當前文件大小」了嗎?我們可以用WINDOWS系統自帶的計算器進行計算,把計算器的「查看」菜單設置為科學型、十六進制、四字(如圖23)。然後用當前文件大小的值減去起始值00000400,得到的結果為000B9A00,那麼我們就在「驗測大小」後填上000B9A00,然後點擊「填加區段」按鈕(如圖24)。最後點擊確定,在新彈出的對話框中點擊運行,不過需要注意的是,在進行此步操作時一定要打開殺毒軟體的所有功能。下面你要做的就是等待……然而光找特徵碼是不夠的,我們還得學會怎樣更改,而關於特徵碼地更改是非常有學問的!這里為了方便廣大讀者能學以致用,在此我只介紹部分理論知識,著重介紹實踐操作,但是我想請大家注意,免殺的方法象你做完免殺的木馬一樣,都有生存時間,而過了這個時間,這種免殺方法就變的不在實用,或者免殺效果大打折扣!所以要想真正成為免殺高手,還的打牢基本功,不斷創造出新的免殺方法,因為我們是在與殺毒軟體廠商的專業技術人員「鬥法」啊!關於需要注意的問題就先講的這,下面我帶大家先來了解一下目前更改特徵碼的辦法。1. 大小寫替換(只適用於文件免殺)適 用 於:出現可識別的英文字母或片語,並且確定其不是相關函數(如輸入表函數)。操作方法:如咱們「實戰演習」的第一節講的一樣,只須將大小寫替換一下就可以了,例如特徵碼中出現了A,你只要將其替換為a即可。原 理:利用WINDOWS系統對大小寫不敏感,而殺毒軟體卻對大小寫非常敏感這一特性達到免殺目的。2. 用00填充適 用 於:幾乎任何情況,但成功率不是非常高。操作方法:例如我們找到了一處特徵碼0009EE7F_00000005,那麼根據這段特徵碼信息我們可以知道它的位置在0009EE7F,大小為5個位元組,也就是0009EE7F-0009EE83這一段內容(如圖25)。
一直跟著文章實踐操作的朋友肯定有疑問,你是怎麼找到那個地址的呢?而我怎麼找不到呢?那是因為WinHex的默認偏移量為decimal模式,我們單擊Offset欄將其改為16進制模式即可(如圖26)。
然後我們有選擇的一處處地用00填充(如圖27)。記住要多試幾次,80%的情況下你都能找到一處既能免殺又不影響程序正常運行的區域。對於定義出的內存特徵碼,只要將其內存地址用一個叫做《便宜量轉換器》的小程序轉換成16進制偏移量,然後在進行相應操作即可。原 理:由於PE文件的特殊格式以及程序編譯語言等問題,使得生成目標代碼的效率並不高,難免出現一些「垃圾信息」,而這些信息存在與否對與程序是否能正常運行並不起決定性的作用,而當木馬的這部分「垃圾信息」被定義為特徵碼時,我們完全可以將其刪除,而刪除的方法就是用無任何意義的00將其替換。3. 跳到空白區域適 用 於:幾乎任何情況,成功率比較高。操作方法:還是以特徵碼0009EE7F_00000005為例子,假如我們使用00填充的方法失敗了那麼不要多想,接下來馬上試試OllyDbg,關於OllyDbg我就不多介紹了,它是非常棒而且非常專業的一個動態反匯編/調試工具,這里我們只用它來幫助我們進行免殺作業,首先應該做的就是將我們的16進制偏移量0009EE7F轉換為內存地址,因為OllyDbg的工作原理是先將程序釋放到內存空間里,然後才能進行相關作業…這里要用到的是一個叫做《便宜量轉換器》的小程序,我們用其轉換完畢後得到的內存地址為0049FA7F(如圖28)。
下面我們用OllyDbg打開我們的木馬服務端,首先找到一處空白區,並域記下這的地址004A24A5,然後找到我們剛轉換過來的地址0049FA7F,先將以0049FA7F開始以下的這三行數據選定,然後單擊右鍵選則[復制]→[到接剪貼板](如圖29)。將其復制到本文文檔里備用,然後在將這三行代碼一一NOP掉(如圖30)。最後右鍵點擊0049FA7F,在彈出的對話框中選擇匯編,並寫入「jmp 004A24A5」這條匯編指令(如圖31)。記住,在點擊[匯編]按鈕之前一定先把「使用 NOP 填充」前面的勾去掉。然後我們記下匯編後0049FA7F的下面那個地址0049FA84(仔細觀察圖31)。好,下面我們回到004A24A5這處剛才找到的空白地址(如圖32)。
然後用剛才匯編的方法把在本文文檔里備用的信息一句句地匯編進去,然後在將最後一句代碼的下一行004A24AA處加入「jmp 0049FA84」這行代碼(如圖33)。然後單擊右鍵→[復制到可執行文件]→[所有修改](如圖34)。
在彈出的對話框中選擇「全部復制」然後保存即可。而對於內存免殺就省去了內存地址轉換這一步了。原 理:大家先看圖35,由圖中可知,正象此方法的名字「跳到空白區域」一樣,這種方法的原理就是將原本含有特徵碼的信息轉移到空白區域,並把原先位置的信息全部NOP掉,並在那裡加一個跳轉指令,讓其跳到004A24A5處,也就是我們找到的空白區域,並把原來在0049FA84的信息移到這里,加完信息後在加一條指令讓其在跳回去,以使程序連貫起來。
4. 上下互換適 用 於:幾乎任何情況,成功率比較高。操作方法:先用OllyDbg載入木馬程序,假定其特徵碼為0009EE7F_00000005,我們還是先用《偏移量轉換器》將其轉換為內存地址,上面我們已經知道0009EE7F對應的內存地址為0049FA7F,然後在OllyDbg中找到相應位置,利用上面「跳到空白區域」里介紹的修改方法將0049FA7F上下兩句代碼調換位置即可。而對於內存免殺就省去了內存地址轉換這一步了。原 理:殺毒軟體的特徵碼定位是嚴格按照相關偏移量於內存地址進行的,而其實我們的應用程序中的機器碼執行順序的先後在一般情況下是沒有死規定的,所以我們只需將其上下互換,殺毒軟體自然就不認識了。5.ADD與SUB 互換適 用 於:在內存特徵碼中出現ADD或 SUB指令的,成功率比較高。操作方法:用OllyDbg載入木馬程序,假定其特徵碼所對應的地址中有ADD或SUB指令,例如00018A88:XXXXX 00000088 ADD ECX 10000000我們可以將ADD ECX 10000000這段機器碼改為SUB ECX F0000000,更改完畢後保存為EXE文件即可。原 理:我們都知道1+1=2,我們也知道1-(-1)=2,上面就是利用了這個原理,其中ADD指令的就是加意思,而SUB則是減的意思。雖然被我們互換了一下,但是最終結果還是一樣的,可是換完之後殺毒軟體就不認識了。到這里,關於特徵碼的查找與修改就講完了,但是除此之外呢?答案是還有許多!!下面我們就一起看看其他免殺方法。4.)其他免殺方法改文件頭:這里所說的改文件頭包括加頭去頭,文件加花。關於加頭去頭,我們還是用OllyDbg。用OllyDbg載入後,OllyDbg會自動停在入口點(如圖36)。
我們將頭三行機器碼復制保存起來,然後找到空白區域,用匯編的方法一一將其寫入(如圖37)。然後在後面寫入一條JMP指令,讓其跳到初始入口點的第四行,相信一直仔細看本文的朋友一定明白其原理,如果忘了的話可以看上面修改特徵碼的第三種方法,原理與這差不多,修改完畢後如下所示:004A2A73 0000 add byte ptr ds:[eax],al004A2A75 0000 add byte ptr ds:[eax],al004A2A77 55 push ebp004A2A78 8BEC mov ebp,esp004A2A7A B9 04000000 mov ecx,4004A2A7F ^ E9 CCF3FFFF jmp Server.004A1E50004A2A84 0000 add byte ptr ds:[eax],al004A2A86 0000 add byte ptr ds:[eax],al004A2A88 0000 add byte ptr ds:[eax],al
上面的add byte ptr ds:[eax],al就是所謂的空白區域,我們看到改完後的頭文件位於004A2A77,所以我們還要用PEditor改一下入口點,打開PEditor後載入文件,將入口點處的地址改為我們的新文件頭地址004A2A77(如圖38),保存後即可。

⑨ c語言中可以用public和protect嗎

public和protect不是C語言的關鍵字,你可以用他們做標識符使用。public、protect一般用在面向對象語言中,表示類的訪問許可權。C語言不是面向對象的。

⑩ c語言如何將一段自定義的buff轉換成可執行的代碼

__declspec(noinline)voidhelloworld()
{
printf("helloworld");
"helloworld"(4221E0h)
004017C5E878A40000callprintf(40BC42h)
004017CA59popecx
}

因為代碼生成的匯編指令call是相對位置的

E8 78 A4 00 00 這個, e8表示相對地址調用,後面78 A4 00 00 表示的 當前的地址和printf函數地址的偏移。


如果自己memcpy復制後,helloworld函數的地址變了,那個call指令和 printf函數的偏移距離也變了。所以就出錯了。


所以這個復制代碼的方式要正常工作的話,這段代碼必須是位置無關的,也就是

Position-independentcode

gcc裡面可以指定pic選項來讓編譯器生成位置無關的代碼。vc裡面找了一下沒找到。

所以只能使用匯編才行了。


charformat[]="%s%s ";
charhello[]="Hello";
charworld[]="world";
staticintprintf_addr=(int)&printf;

__declspec(noinline)voidhelloworld()
{
//printf("helloworld");
__asm
{
moveax,offsetworld
pusheax
moveax,offsethello
pusheax
moveax,offsetformat
pusheax
//callprintf
moveax,printf_addr
calleax
//
//
popebx
popebx
popebx
}
}


這樣寫之後,這個call指令那裡,生成的機器碼採用的是絕對值的FF,就可以正常工作了。


所以這種用法的話,還是自己手寫位置無關的匯編才行,或者需要會自己做重定位的。就像上面那個一樣 自己知道call指令的那裡的話,可以自己修改偏移為正確的值。