您的位置:首页精文荟萃软件资讯 → Win2000/XP替换正在使用的系统文件

Win2000/XP替换正在使用的系统文件

时间:2004/10/7 18:26:00来源:本站整理作者:蓝点我要评论(0)

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

  要安静地替换正在使用的系统文件要解决两个问题:
  1. 替换正在使用的文件.
  2. 在替换系统文件时不显示插CD的对话框.

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

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

-------------------cut zap.c---------
#include

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 fileNeedToDeln", n);
    exit(0);
}

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

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

    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
#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. :) *nn");

    if (argc != 2)
        usage(argv[0]);

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

    if (Init()) {
        printf("debug privilege setn");
    } else {
        printf("error on get debug privilegen");
        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("Win2000n");
        }
        else {//if((DWORD)(HIBYTE(LOWORD(dwVersion))) = 1)             //Windows XP
            hSfc = LoadLibrary("sfc_os.dll");
            printf("Windows XPn");
        }
    }    
    //else if ()   //2003?
    else {
        printf("unsupported versionn");
    }

    pfnCloseEvents = (CLOSEEVENTS)GetProcAddress(hSfc,
                                                MAKEINTRESOURCE(2));
    if(pfnCloseEvents == NULL){
        printf("Load the sfc fuction failedn");
        FreeLibrary(hSfc);
        return(0);
    }

    FreeLibrary(hSfc);

    dwThread = InjectThread(&Process,
                            pfnCloseEvents);
   
    if(dwThread == 0){
        printf("failedn");
    }
    else{
        printf("OKn");
    }

    CloseHandle(Process.ProcessHandle);
    return(0);

}


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

相关阅读 Windows错误代码大全 Windows错误代码查询激活windows有什么用Mac QQ和Windows QQ聊天记录怎么合并 Mac QQ和Windows QQ聊天记录Windows 10自动更新怎么关闭 如何关闭Windows 10自动更新windows 10 rs4快速预览版17017下载错误问题Win10秋季创意者更新16291更新了什么 win10 16291更新内容windows10秋季创意者更新时间 windows10秋季创意者更新内容kb3150513补丁更新了什么 Windows 10补丁kb3150513是什么

文章评论
发表评论

热门文章 360快剪辑怎么使用 36金山词霸如何屏幕取词百度收购PPS已敲定!3

最新文章 微信3.6.0测试版更新了微信支付漏洞会造成哪 360快剪辑怎么使用 360快剪辑软件使用方法介酷骑单车是什么 酷骑单车有什么用Apple pay与支付宝有什么区别 Apple pay与贝贝特卖是正品吗 贝贝特卖网可靠吗

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方电脑闹钟怎么设置 win7电脑闹钟怎么设置office2013安装教程图解:手把手教你安装与qq影音闪退怎么办 QQ影音闪退解决方法VeryCD镜像网站逐个数,电驴资料库全集同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载EDiary——一款好用的电子日记本