首页 电脑 电脑学堂 查看内容

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

2004-9-29 20:05 596 0

摘要:     要安静地替换正在使用的系统文件要解决两个问题:   1. 替换正在使用的文件.   2. 在替换系统文件时不显示插CD的对...
关键词: nbsp process text 函数 SfcDisable 文件 printf DWORD return 系统

    要安静地替换正在使用的系统文件要解决两个问题:   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+上测试过.     本文的缺点是替换的系统文件只能在重启后生效, 写完了.参考文献:    http://www.chapeaux-noirs.org/win/
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部