今天懒得干活,把google到的Debug_for_Free.c(现在google到的链接好像连不过去了,可以用google快照看到)转换&改进了一下,或许有人用的到.
unit Unit1;
(********************************)
(* Debug for Free *)
(* Works on Win2k ONLY! *)
(* *)
(*Coverted from Debug_for_Free.c*)
(* *)
(* Covert & Improved by tt.t *)
(* *)
(* Dec. 17, 2005 *)
(********************************)
(*
作用: Win2k下的DebugSetProcessKillOnExit(FALSE)
原理: Win2k下调试器结束时,Smss.exe会用NtTerminateThread和NtTerminateProcess
强行将被调试进程结束,只要nop掉相应代码就可取得和xp的DebugSetProcessKillOnExit(FALSE)
一样的结果,即调试器结束,被调试程序继续运行.但这种方法并未将被调试程序的调
试信息去掉, 因此调试器结束后,被调试程序无法被其他调试器附加.
难点: 基本没有,只是找到Patch的位置比较麻烦,这里采用了查找硬编码的方法.
注意: 只能用于Win2k系统!这种方法在Win2k + sp3, sp4中文系统上测试通过,
但仍有可能会造成系统重启等后果,使用前注意!纯属无聊之做,出问题别找我.
测试方法: 用任意ring3调试器载入任意程序,并运行.在任务管理器中结束调试器进程,
如调试器关闭而被调试程序仍正常运行则说明成功.不可直接关闭调试器来测试,
因为调试器正常退出时,可能会主动关闭被调试程序.
*)
interface
uses
Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses TLHelp32, JwaWinNt, JwaWinBase, JwaWinType, JwaWinError;
function GetModuleFileNameExA(hProcess: THandle; hModule: HMODULE; lpFilename: PChar;
nSize: DWord): integer;stdcall;external 'PSAPI.DLL';
const
Len_NtTerminateThread = 14; //code length
HC_NtTerminateThread = $01000468;//HardCode: $68 04 00 01
Len_NtTerminateProcess = 10; //code length
HC_NtTerminateProcess = $2473FF57;//HardCode: $57 FF 73 24
var
Ptr_NtTerminateThread, Ptr_NtTerminateProcess: Cardinal;
//Patch的AV.
//在我测试的机器上2个的AV是一样的,分别是$48584331和$485843BE.
hSmss: Cardinal;
OldProtect: Cardinal;
NopBuf: Array [0..20] of Byte; //Nop * 20
NtTerminateThreadBuf: Array [0..Len_NtTerminateThread - 1] of Byte;
//保存patch前的内容
NtTerminateProcessBuf: Array [0..Len_NtTerminateProcess - 1] of Byte;
//保存patch前的内容
i: Cardinal;
function EnabledDebugPrivilege(const bEnabled: Boolean):Boolean; //提升权限
var
hToken: THandle;
tp: TOKEN_PRIVILEGES;
a: DWORD;
const
SE_DEBUG_NAME = 'SeDebugPrivilege';
begin
Result:=False;
if (OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken)) then
begin
tp.PrivilegeCount :=1;
LookupPrivilegeValue(nil, SE_DEBUG_NAME, tp.Privileges[0].Luid);
if bEnabled then
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
tp.Privileges[0].Attributes := 0;
a:=0;
AdjustTokenPrivileges(hToken, False, @tp, SizeOf(tp), nil, @a);
Result:= GetLastError = ERROR_SUCCESS;
CloseHandle(hToken);
end;
end;
function DoFix: Bool; //Patch
function Fix(Ptr: Pointer; var DesBuf: Array of Byte; Len: integer): Bool;
var
Buf: Array [0..20] of Byte;
begin
result := true;
result := result and ReadProcessMemory(hSmss, Ptr, @Buf[0], Len, @i);
if Ord(Buf[0]) <> $90 then
begin
CopyMemory(@DesBuf[0], @Buf[0], Len);
result := result and WriteProcessMemory(hSmss, Ptr, @NopBuf[0], Len, @i);
end
else
result := false;
end;
begin
result := true;
result := result and VirtualProtectEx(hSmss, Pointer(Ptr_NtTerminateThread), 128,
PAGE_EXECUTE_READWRITE, @OldProtect);
result := result and Fix(Pointer(Ptr_NtTerminateThread), NtTerminateThreadBuf,
Len_NtTerminateThread);
result := result and Fix(Pointer(Ptr_NtTerminateProcess), NtTerminateProcessBuf,
Len_NtTerminateProcess);
result := result and VirtualProtectEx(hSmss, Pointer(Ptr_NtTerminateThread), 128,
OldProtect, @OldProtect);
end;
function UndoFix: Bool;
function Fix(Ptr: Pointer; SrcBuf: Array of Byte; Len: integer): Bool;
var
Buf: Array [0..20] of Byte;
begin
result := true;
result := result and ReadProcessMemory(hSmss, Ptr, @Buf[0], Len, @i);
if Ord(Buf[0]) = $90 then
begin
result := result and WriteProcessMemory(hSmss, Ptr, @SrcBuf[0], Len, @i);
end
else
result := false;
end;
begin
if (Ord(NtTerminateThreadBuf[0]) = 0) or (Ord(NtTerminateProcessBuf[0]) = 0) then
begin
result := false;
exit;
end;
result := true;
result := result and VirtualProtectEx(hSmss, Pointer(Ptr_NtTerminateThread), 256,
PAGE_EXECUTE_READWRITE, @OldProtect);
result := result and Fix(Pointer(Ptr_NtTerminateThread), NtTerminateThreadBuf,
Len_NtTerminateThread);
result := result and Fix(Pointer(Ptr_NtTerminateProcess), NtTerminateProcessBuf,
Len_NtTerminateProcess);
result := result and VirtualProtectEx(hSmss, Pointer(Ptr_NtTerminateThread), 256,
OldProtect, @OldProtect);
end;
function Search4Hardcode: Bool; //取得Patch位置的AV.
var
TmpSmss: TMemoryStream;
PFileHeader: PImageFileHeader;
POptionalHeader32: PImageOptionalHeader32;
PSectionHeader: PImageSectionHeader;
l: integer;
SysDir: PChar;
Ptr: PByte;
f1, f2: Bool;
begin
result := false;
l := GetSystemDirectory(nil, 0);
GetMem(SysDir, l);
GetSystemDirectory(SysDir, l);
TmpSmss := TMemoryStream.Create;
try
TmpSmss.LoadFromFile(SysDir + '\SMSS.EXE');
PFileHeader := PImageFileHeader(Longint(TmpSmss.Memory) +
PImageDosHeader(TmpSmss.Memory)^.e_lfanew + 4);
POptionalHeader32 := PImageOptionalHeader32(DWORD(PFileHeader) +
IMAGE_SIZEOF_FILE_HEADER);
PSectionHeader := PImageSectionHeader(DWORD(POptionalHeader32) +
PFileHeader^.SizeOfOptionalHeader);
f1 := false;
f2 := false;
for i := 0 to PFileHeader^.NumberOfSections - 1 do //遍历各个Section
begin
Ptr := PByte(Cardinal(TmpSmss.Memory) + PSectionHeader^.PointerToRawData);
for i := 0 to PSectionHeader^.SizeOfRawData - 1 do
//在Section中查找需Patch的Hardcode
begin
if Ptr^ = LoByte(LoWord(HC_NtTerminateThread)) then //第一Byte相同?
begin
if PDWORD(Ptr)^ = HC_NtTerminateThread then //整个DWORD相同?
begin
Ptr_NtTerminateThread := POptionalHeader32^.ImageBase +
PSectionHeader^.VirtualAddress + i;
//计算得到Patch位置的AV.
//Smss.exe的基址一般就是其PE中指定的ImageBase.
//所以内存中Smss.exe需要Patch的位置就其在PE文件中的AV.
f1 := true;
end;
end
else if Ptr^ = LoByte(LoWord(HC_NtTerminateProcess)) then
if PDWORD(Ptr)^ = HC_NtTerminateProcess then
begin
Ptr_NtTerminateProcess := POptionalHeader32^.ImageBase +
PSectionHeader^.VirtualAddress + i;
f2 := true;
end;
if f1 and f2 then Break; //2处Patch都已找到.
inc(Ptr);
end;
if f1 and f2 then
begin
result := true;
Break;
end;
inc(PSectionHeader);
end;
finally
TmpSmss.Free;
FreeMem(SysDir);
end;
end;
function FindSmss(var Handle: Cardinal): Bool;
//获取Smss.exe的ProcessId,并打开得到Process Handle.
const
SmssPath = '\SYSTEMROOT\SYSTEM32\SMSS.EXE';
var
lppe: TProcessEntry32;
sHandle:cardinal;
Found: bool;
hp: cardinal;
ExePath: PChar;
begin
result := false;
GetMem(ExePath, MAX_PATH);
sHandle := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
Found := Process32First(sHandle, lppe);
while found do
begin
hp := OpenProcess(PROCESS_ALL_ACCESS, false, lppe.th32ProcessID);
GetModuleFileNameExA(hp, 0, ExePath, MAX_PATH); //取完全路径
if UpperCase(ExePath) = SmssPath then
begin
Handle := hp;
result := true;
Break;
end;
Found := Process32Next(sHandle, lppe);
CloseHandle(hp);
end;
CloseHandle(sHandle);
FreeMem(ExePath);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
if GetVersion and 255 <> 5 then
begin
Showmessage('Works on Win2k Only!!');
Halt;
end;
Search4Hardcode; //取得Patch位置的AV.
EnabledDebugPrivilege(true); //提升权限
FillMemory(@NopBuf[0], 20, $90);
ZeroMemory(@NtTerminateThreadBuf[0], Len_NtTerminateThread);
ZeroMemory(@NtTerminateProcessBuf[0], Len_NtTerminateProcess);
if not FindSmss(hSmss) then
//获取Smss.exe的ProcessId,并打开得到Process Handle.
showmessage('Smss.exe not found?!');
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UndoFix;
CloseHandle(hSmss);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if not DoFix then //Patch
showmessage('Do fix failed!')
else
Label1.Caption := 'Patched!';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if not UndoFix then //恢复
showmessage('Do UndoFix failed!')
else
Label1.Caption := 'Not Patched!';
end;
end.
=========================================================================
object Form1: TForm1
Left = 192
Top = 107
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'Form1'
ClientHeight = 140
ClientWidth = 239
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 8
Top = 16
Width = 151
Height = 29
Caption = 'Not Patched!'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -24
Font.Name = 'MS Sans Serif'
Font.Style = [fsBold]
ParentFont = False
end
object Button1: TButton
Left = 8
Top = 56
Width = 225
Height = 41
Caption = 'DoFix'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 8
Top = 96
Width = 225
Height = 41
Caption = 'UndoFix'
TabOrder = 1
OnClick = Button2Click
end
end