FPPS4/sys/kern/kern_patcher.pas

580 lines
16 KiB
Plaintext

unit kern_patcher;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
kern_stub;
procedure patcher_process_section(_imgp,data,vaddr:Pointer;filesz,memsz:QWORD;prot:Byte);
implementation
uses
kern_thr,
md_map,
vm_patch_link,
trap,
x86_index_instr,
kern_rtld;
{
64 48 A1 [0000000000000000] mov rax,fs:[$0000000000000000] -> 65 48 A1 [0807000000000000] mov rax,gs:[$0000000000000708]
64 48 8B 04 25 [00000000] mov rax,fs:[$00000000] -> 65 48 8B 04 25 [08070000] mov rax,gs:[$00000708]
64 48 8B 0C 25 [00000000] mov rcx,fs:[$00000000] -> 65 48 8B 0C 25 [08070000] mov rcx,gs:[$00000708]
64 48 8B 14 25 [00000000] mov rdx,fs:[$00000000] -> 65 48 8B 14 25 [08070000] mov rdx,gs:[$00000708]
64 48 8B 1C 25 [00000000] mov rbx,fs:[$00000000] -> 65 48 8B 1C 25 [08070000] mov rbx,gs:[$00000708]
64 48 8B 24 25 [00000000] mov rsp,fs:[$00000000] -> 65 48 8B 24 25 [08070000] mov rsp,gs:[$00000708]
64 48 8B 2C 25 [00000000] mov rbp,fs:[$00000000] -> 65 48 8B 2C 25 [08070000] mov rbp,gs:[$00000708]
64 48 8B 34 25 [00000000] mov rsi,fs:[$00000000] -> 65 48 8B 34 25 [08070000] mov rsi,gs:[$00000708]
64 48 8B 3C 25 [00000000] mov rdi,fs:[$00000000] -> 65 48 8B 3C 25 [08070000] mov rdi,gs:[$00000708]
64 4C 8B 04 25 [00000000] mov r8 ,fs:[$00000000] -> 65 4C 8B 04 25 [08070000] mov r8 ,gs:[$00000708]
64 4C 8B 0C 25 [00000000] mov r9 ,fs:[$00000000] -> 65 4C 8B 0C 25 [08070000] mov r9 ,gs:[$00000708]
64 4C 8B 14 25 [00000000] mov r10,fs:[$00000000] -> 65 4C 8B 14 25 [08070000] mov r10,gs:[$00000708]
64 4C 8B 1C 25 [00000000] mov r11,fs:[$00000000] -> 65 4C 8B 1C 25 [08070000] mov r11,gs:[$00000708]
64 4C 8B 24 25 [00000000] mov r12,fs:[$00000000] -> 65 4C 8B 24 25 [08070000] mov r12,gs:[$00000708]
64 4C 8B 2C 25 [00000000] mov r13,fs:[$00000000] -> 65 4C 8B 2C 25 [08070000] mov r13,gs:[$00000708]
64 4C 8B 34 25 [00000000] mov r14,fs:[$00000000] -> 65 4C 8B 34 25 [08070000] mov r14,gs:[$00000708]
64 4C 8B 3C 25 [00000000] mov r15,fs:[$00000000] -> 65 4C 8B 3C 25 [08070000] mov r15,gs:[$00000708]
}
{
90488B80 [11111111] mov rax,[rax+$11111111]
90488B89 [11111111] mov rcx,[rcx+$11111111]
90488B92 [11111111] mov rdx,[rdx+$11111111]
90488B9B [11111111] mov rbx,[rbx+$11111111]
488BA424 [11111111] mov rsp,[rsp+$11111111]
90488BAD [11111111] mov rbp,[rbp+$11111111]
90488BB6 [11111111] mov rsi,[rsi+$11111111]
90488BBF [11111111] mov rdi,[rdi+$11111111]
904D8B80 [11111111] mov r8 ,[r8 +$11111111]
904D8B89 [11111111] mov r9 ,[r9 +$11111111]
904D8B92 [11111111] mov r10,[r10+$11111111]
904D8B9B [11111111] mov r11,[r11+$11111111]
4D8BA424 [11111111] mov r12,[r12+$11111111]
904D8BAD [11111111] mov r13,[r13+$11111111]
904D8BB6 [11111111] mov r14,[r14+$11111111]
904D8BBF [11111111] mov r15,[r15+$11111111]
}
{
[48 b8 | 10 01 00 00 00 00 00 00]:MOV RAX,0x110
[49 89 ca]:MOV R10,RCX
[0f 05]:SYSCALL
[72 01]:JC LAB
[c3]:RET
///////////////////
[48 c7 c0 | dd 01 00 00]:MOV RAX,0x1dd
[49 89 ca]:MOV R10,RCX
[0f 05]:SYSCALL
[72 01]:JC LAB
[c3]:RET
//////////
48 c7 c0 01 | 00 00 00 MOV RAX,0x1
49 89 ca MOV R10,RCX
0f 05 SYSCALL
41 5c POP R12
5b POP RBX
[00 00 00 | 49 89 ca | 0f 05 | 41 5c]
//////////
48 c7 c0 fb | 00 00 00 MOV RAX,0xfb
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 1f JC LAB_
83 fa 00 CMP EDX,0x0
75 04 JNZ LAB_
41 5c POP R12
[00 00 00 | 49 89 ca | 0f 05 | 72 1f]
//////////
48 c7 c0 01 | 00 00 00 MOV RAX,0x1
49 89 ca MOV R10,RCX
0f 05 SYSCALL
41 5c POP R12
5b POP RBX
//////////
48 c7 c0 3b | 00 00 00 MOV RAX,0x3b
49 89 ca MOV R10,RCX
0f 05 SYSCALL
48 8d 15 c0 LEA RDX,[FUN_]
ff ff ff
ff e2 JMP RDX=>FUN_
[00 00 00 | 49 89 ca | 0f 05 | 48 8d]
//////////
48 c7 c0 a5 | 01 00 00 MOV RAX,0x1a5
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 06 JC LAB_
48 83 c4 08 ADD RSP,0x8
ff e6 JMP RSI
[01 00 00 | 49 89 ca | 0f 05 | 72 06]
//////////
48 c7 c0 2a | 00 00 00 MOV RAX,0x2a
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 0d JC LAB_
89 07 MOV dword ptr
[00 00 00 | 49 89 ca | 0f 05 | 72 0d]
//////////
48 c7 c0 37 | 00 00 00 MOV RAX,0x37
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 02 JC LAB_
48 cf IRETQ
[00 00 00 | 49 89 ca | 0f 05 | 72 02]
//////////
48 c7 c0 32 | 00 00 00 MOV RAX,0x32
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 0e JC LAB_
48 8d 15 a3 e1 08 00 LEA RDX,[DAT_]
[00 00 00 | 49 89 ca | 0f 05 | 72 0e]
//////////
48 c7 c0 42 | 00 00 00 MOV RAX,0x42
49 89 ca MOV R10,RCX
0f 05 SYSCALL
72 02 JC LAB_
ff e6 JMP RSI
[00 00 00 | 49 89 ca | 0f 05 | 72 02]
//////////
48 c7 c0 54 | 01 00 00 MOV RAX,0x154
49 89 ca MOV R10,RCX
0f 05 SYSCALL
5f POP RDI
48 81 bf 18 CMP qword ptr [RDI + 0x118],0x20001
01 00 00 01
00 02 00
[01 00 00 | 49 89 ca | 0f 05 | 5f 48]
//////////
48 c7 c0 c6 | 01 00 00 MOV RAX,0x1c6
49 89 ca MOV R10,RCX
0f 05 SYSCALL
c3 RET
90 ?? 90h
[01 00 00 | 49 89 ca | 0f 05 | c3 90]
//////////
0 1 2 3 4 5 6 7 8 9
[0X 00 00 | 49 89 ca | 0f 05 | 41 5c]
[0X 00 00 | 49 89 ca | 0f 05 | 72 01]
[0X 00 00 | 49 89 ca | 0f 05 | 72 1f]
[0X 00 00 | 49 89 ca | 0f 05 | 48 8d]
[0X 00 00 | 49 89 ca | 0f 05 | 72 06]
[0X 00 00 | 49 89 ca | 0f 05 | 72 0d]
[0X 00 00 | 49 89 ca | 0f 05 | 72 02]
[0X 00 00 | 49 89 ca | 0f 05 | 72 0e]
[0X 00 00 | 49 89 ca | 0f 05 | 5f 48]
[0X 00 00 | 49 89 ca | 0f 05 | c3 90]
X=0,1,2
}
{
jmpq 0(%rip) -> [FF 25 | 00 00 00 00]
callq 0(%rip) -> [FF 15 | 00 00 00 00]
jmpl [32] -> [E9 | 00 00 00 00]
calll [32] -> [E8 | 00 00 00 00]
}
type
{
p_patch_base_long=^t_patch_base_long;
t_patch_base_long=packed record
len :Byte ; //12
inst:array[0..2] of Byte;
addr:Int64; //teb_tcb/teb_gsbase
end;
p_patch_base_short=^t_patch_base_short;
t_patch_base_short=packed record
len :Byte ; //9
inst:array[0..4] of Byte;
addr:Integer; //teb_tcb/teb_gsbase
end;
t_patch_inst=packed record
case Byte of
0:(A:t_patch_base_long);
1:(B:t_patch_base_short);
2:(C:array[0..11] of Byte);
end;
}
p_jmpq64_trampoline=^t_jmpq64_trampoline;
t_jmpq64_trampoline=packed record
inst :Word; //FF 25
offset:DWORD; //00
addr :QWORD;
end;
p_call32_trampoline=^t_call32_trampoline;
t_call32_trampoline=packed record
inst:Byte; //E8
addr:Integer;
end;
p_jmp32_trampoline=^t_jmp32_trampoline;
t_jmp32_trampoline=t_call32_trampoline;
p_mov_rel_base32=^t_mov_rel_base32;
t_mov_rel_base32=packed record
inst:array[0..4] of Byte;
addr:Integer; //teb_tcb/teb_gsbase
end;
p_mov_rel32=^t_mov_rel32;
t_mov_rel32=packed record
inst:array[0..3] of Byte;
addr:Integer; //offset
end;
p_base_data_trampoline=^t_base_data_trampoline;
t_base_data_trampoline=packed record
bseg:t_mov_rel_base32;
data:t_mov_rel32;
bjmp:t_jmpq64_trampoline;
end;
const
{
patch_table:array[0..33] of t_patch_inst=(
(B:(len: 9;inst:($65,$48,$8B,$04,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$0C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$14,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$1C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$24,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$2C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$34,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$48,$8B,$3C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$04,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$0C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$14,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$1C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$24,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$2C,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$34,$25);addr:teb_tcb )),
(B:(len: 9;inst:($65,$4C,$8B,$3C,$25);addr:teb_tcb )),
(A:(len:12;inst:($65,$48,$A1 );addr:teb_tcb )),
//
(B:(len: 9;inst:($65,$48,$8B,$04,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$0C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$14,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$1C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$24,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$2C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$34,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$48,$8B,$3C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$04,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$0C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$14,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$1C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$24,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$2C,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$34,$25);addr:teb_gsbase)),
(B:(len: 9;inst:($65,$4C,$8B,$3C,$25);addr:teb_gsbase)),
(A:(len:12;inst:($65,$48,$A1 );addr:teb_gsbase))
);
}
patch_fs_table:array[0..15] of t_mov_rel_base32=(
(inst:($65,$48,$8B,$04,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$0C,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$14,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$1C,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$24,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$2C,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$34,$25);addr:teb_fsbase),
(inst:($65,$48,$8B,$3C,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$04,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$0C,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$14,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$1C,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$24,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$2C,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$34,$25);addr:teb_fsbase),
(inst:($65,$4C,$8B,$3C,$25);addr:teb_fsbase)
);
patch_gs_table:array[0..15] of t_mov_rel_base32=(
(inst:($65,$48,$8B,$04,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$0C,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$14,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$1C,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$24,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$2C,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$34,$25);addr:teb_gsbase),
(inst:($65,$48,$8B,$3C,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$04,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$0C,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$14,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$1C,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$24,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$2C,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$34,$25);addr:teb_gsbase),
(inst:($65,$4C,$8B,$3C,$25);addr:teb_gsbase)
);
patch_mov_rel_table:array[0..15] of t_mov_rel32=(
(inst:($90,$48,$8B,$80);addr:0),
(inst:($90,$48,$8B,$89);addr:0),
(inst:($90,$48,$8B,$92);addr:0),
(inst:($90,$48,$8B,$9B);addr:0),
(inst:($48,$8B,$A4,$24);addr:0),
(inst:($90,$48,$8B,$AD);addr:0),
(inst:($90,$48,$8B,$B6);addr:0),
(inst:($90,$48,$8B,$BF);addr:0),
(inst:($90,$4D,$8B,$80);addr:0),
(inst:($90,$4D,$8B,$89);addr:0),
(inst:($90,$4D,$8B,$92);addr:0),
(inst:($90,$4D,$8B,$9B);addr:0),
(inst:($4D,$8B,$A4,$24);addr:0),
(inst:($90,$4D,$8B,$AD);addr:0),
(inst:($90,$4D,$8B,$B6);addr:0),
(inst:($90,$4D,$8B,$BF);addr:0)
);
c_jmpq64_trampoline:t_jmpq64_trampoline=(inst:$25FF;offset:0;addr:0);
c_call32_trampoline:t_call32_trampoline=(inst:$E8;addr:0);
c_jmpl32_trampoline:t_jmp32_trampoline =(inst:$E9;addr:0);
procedure patch_original(const info:t_instr_index_info;delta:Integer;addr_out:Pointer);
var
trampoline:t_call32_trampoline;
begin
//fill nop
FillChar(addr_out^,info.inlen,$90);
case info.instr of
I_MOV_BASE32:trampoline:=c_jmpl32_trampoline;
I_MOV_BASE64:trampoline:=c_jmpl32_trampoline;
I_SYSCALL :trampoline:=c_call32_trampoline;
else;
end;
trampoline.addr:=delta;
p_call32_trampoline(addr_out)^:=trampoline;
end;
procedure vm_add_mov_base_patch(const info:t_instr_index_info;_obj,vaddr,addr_out:Pointer);
var
stub:p_stub_chunk;
trampoline:t_base_data_trampoline;
delta:Int64;
begin
stub:=p_alloc(vaddr,SizeOf(t_base_data_trampoline),True);
delta:=Int64(@stub^.body)-(Int64(vaddr)+SizeOf(t_call32_trampoline));
Assert(abs(delta)<High(Integer),'vm_add_mov_base_patch');
patch_original(info,Integer(delta),addr_out);
case info.sbase of
FSBASE:trampoline.bseg:=patch_fs_table[info.inreg];
GSBASE:trampoline.bseg:=patch_gs_table[info.inreg];
else;
end;
Assert(info.osize=4,'info.osize=4');
trampoline.data:=patch_mov_rel_table[info.inreg];
trampoline.data.addr:=Integer(info.offst);
trampoline.bjmp:=c_jmpq64_trampoline;
trampoline.bjmp.addr:=(Int64(vaddr)+SizeOf(t_call32_trampoline));
p_base_data_trampoline(@stub^.body)^:=trampoline;
md_cacheflush(@stub^.body,SizeOf(trampoline),ICACHE);
case info.sbase of
FSBASE:vm_add_patch_link(_obj,vaddr,info.inlen,pt_fsbase,stub);
GSBASE:vm_add_patch_link(_obj,vaddr,info.inlen,pt_gsbase,stub);
else;
end;
end;
procedure vm_add_syscall_patch(const info:t_instr_index_info;_obj,vaddr,addr_out:Pointer);
var
stub:p_stub_chunk;
trampoline:t_jmpq64_trampoline;
delta:Int64;
begin
stub:=p_alloc(vaddr,SizeOf(t_jmpq64_trampoline),True);
delta:=Int64(@stub^.body)-(Int64(vaddr)+SizeOf(t_call32_trampoline));
Assert(abs(delta)<High(Integer),'vm_add_syscall_patch');
patch_original(info,Integer(delta),addr_out);
trampoline:=c_jmpq64_trampoline;
trampoline.addr:=QWORD(@fast_syscall);
p_jmpq64_trampoline(@stub^.body)^:=trampoline;
md_cacheflush(@stub^.body,SizeOf(trampoline),ICACHE);
vm_add_patch_link(_obj,vaddr,info.inlen,pt_syscall,stub);
end;
procedure vm_add_patch(const info:t_instr_index_info;_obj,vaddr,addr_out:Pointer);
begin
case info.instr of
I_MOV_BASE32:vm_add_mov_base_patch(info,_obj,vaddr,addr_out);
I_MOV_BASE64:vm_add_mov_base_patch(info,_obj,vaddr,addr_out);
I_SYSCALL :vm_add_syscall_patch (info,_obj,vaddr,addr_out);
else;
end;
end;
procedure patcher_process_section(_imgp,data,vaddr:Pointer;filesz,memsz:QWORD;prot:Byte);
var
addr:Pointer;
pend:Pointer;
info:t_instr_index_info;
b:Boolean;
fs_count:Integer;
gs_count:Integer;
sv_count:Integer;
imgp:p_image_params;
{
procedure do_patch_base_zero(addr:PByte;i:Integer;ptype:t_patch_type);
var
v:Pointer;
begin
Move(patch_table[i].C[1],addr^,patch_table[i].C[0]);
v:=vaddr+(Int64(addr)-Int64(data));
vm_add_patch_link(imgp^.obj,v,ptype,nil);
end;
procedure do_patch_syscall(addr:PByte);
var
v:Pointer;
begin
v:=vaddr+(Int64(addr)-Int64(data));
vm_add_syscall_patch(imgp^.obj,v,addr);
end;
}
procedure do_patch_syscall(addr:PByte);
var
v:Pointer;
begin
v:=vaddr+(Int64(addr)-Int64(data));
vm_add_patch(info,imgp^.obj,v,addr);
end;
begin
Assert(_imgp<>nil,'patcher_process_section');
imgp:=_imgp;
{
if Pos('libkernel',imgp^.execpath)<>0 then
begin
//103040
if (prot=3) then
begin
if (memsz>103040) then
begin
PInteger(data+103040)^:=-1;
end;
end;
end;
}
Exit;
fs_count:=0;
gs_count:=0;
sv_count:=0;
addr:=data;
pend:=addr+filesz;
repeat
info:=Default(t_instr_index_info);
b:=IndexInstr(addr,pend,info);
if (not b) then Break;
do_patch_syscall(addr);
case info.instr of
I_MOV_BASE32:Inc(fs_count);
I_MOV_BASE64:Inc(gs_count);
I_SYSCALL :Inc(sv_count);
else;
end;
Inc(addr,info.inlen);
until false;
Writeln('[patcher_vaddr]:0x',HexStr(qword(vaddr),12),'..',HexStr(qword(vaddr)+filesz,12));
Writeln(' fs_count:',fs_count);
Writeln(' gs_count:',gs_count);
Writeln(' sv_count:',sv_count);
Writeln;
//readln;
end;
end.