This commit is contained in:
Pavel 2023-07-26 23:21:06 +03:00
parent 798b0b2cce
commit 6d2a57bd31
9 changed files with 316 additions and 121 deletions

View File

@ -39,7 +39,8 @@ implementation
uses
errno,
elf_nid_utils;
elf_nid_utils,
kern_stub;
function convert_raw_symbol_str_to_base64(symbol:pchar):RawByteString;
var
@ -363,6 +364,45 @@ begin
end;
end;
//48 8D 3D 00 00 00 00 lea rdi,[rip+$00000000] lea (%rip),%rdi
type
p_jmpq64_trampoline=^t_jmpq64_trampoline;
t_jmpq64_trampoline=packed record
lea:array[0..6] of Byte;
//
inst :Word; //FF 25
offset:DWORD; //00
addr :QWORD;
str :PChar;
end;
const
c_jmpq64_trampoline:t_jmpq64_trampoline=(lea:($48,$8D,$3D,$F9,$FF,$FF,$FF);inst:$25FF;offset:0;addr:0);
procedure _unresolve_symbol(data:p_jmpq64_trampoline);
begin
Writeln('_unresolve_symbol:',data^.str);
readln;
end;
function get_unresolve_ptr(str:PChar):Pointer;
var
stub:p_stub_chunk;
begin
stub:=p_alloc(nil,SizeOf(t_jmpq64_trampoline));
p_jmpq64_trampoline(@stub^.body)^:=c_jmpq64_trampoline;
p_jmpq64_trampoline(@stub^.body)^.addr:=QWORD(@_unresolve_symbol);
p_jmpq64_trampoline(@stub^.body)^.str:=str;
Result:=@stub^.body;
end;
//kern_stub
function find_symdef(symnum:QWORD;refobj:p_lib_info;var defobj_out:p_lib_info;flags:DWORD;cache:p_SymCache):p_elf64_sym;
var
req:t_SymLook;
@ -370,8 +410,14 @@ var
ref:p_elf64_sym;
defobj:p_lib_info;
str:pchar;
count:Integer;
err:Integer;
ST_BIND:Integer;
nModuleId,nLibraryId:WORD;
nNid:QWORD;
fname:RawByteString;
begin
Result:=nil;
@ -389,8 +435,8 @@ begin
def:=nil;
defobj_out:=nil;
err:=refobj^.rel_data^.symtab_size div SizeOf(elf64_sym);
if (symnum<=err) then Exit(nil);
count:=refobj^.rel_data^.symtab_size div SizeOf(elf64_sym);
if (symnum>=count) then Exit(nil);
ref:=refobj^.rel_data^.symtab_addr + symnum;
@ -411,9 +457,20 @@ begin
req:=Default(t_SymLook);
req.symbol:=str;
req.flags :=(flags or SYMLOOK_MANGLED);
req.flags :=(flags{ or SYMLOOK_MANGLED});
req.obj :=refobj;
if DecodeEncName(str,nModuleId,nLibraryId,nNid) then
begin
req.modname:=get_mod_name(refobj,nModuleId);
req.libname:=get_lib_name(refobj,nLibraryId);
fname:=BaseEncName(str);
req.name:=pchar(fname);
end;
//convert_mangled_name_to_long
//req.libname
//req.name
@ -432,6 +489,15 @@ begin
begin
def :=@dynlibs_info.sym_zero;
defobj:=dynlibs_info.libprogram;
end else
begin
dynlibs_info.sym_nops.st_info :=(STB_GLOBAL shl 4) or STT_NOTYPE;
dynlibs_info.sym_nops.st_shndx:=SHN_UNDEF;
dynlibs_info.sym_nops.st_value:=-Int64(dynlibs_info.libprogram^.relocbase)+Int64(get_unresolve_ptr(str));
def :=@dynlibs_info.sym_nops;
defobj:=dynlibs_info.libprogram;
end;
end;

View File

@ -9,93 +9,16 @@ uses
mqueue,
kern_stub;
type
t_patch_type=(pt_fsbase,pt_gsbase,pt_syscall);
p_patch_node=^t_patch_node;
t_patch_node=record
link :TAILQ_ENTRY;
vaddr:Pointer;
ptype:t_patch_type;
stub :p_stub_chunk;
end;
procedure add_patch_link (_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
procedure free_patch_link(_obj:Pointer;node:p_patch_node);
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
procedure patcher_process_section(_obj,data,vaddr:Pointer;filesz:QWORD);
implementation
uses
hamt,
kern_rwlock,
kern_thr,
vm,
vmparam,
vm_map,
vm_mmap,
vm_object,
vm_pmap,
vm_patch_link,
trap;
procedure add_patch_link(_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
var
obj:vm_object_t;
node:p_patch_node;
begin
Writeln('patch:vaddr=0x',HexStr(vaddr),' type:',ptype);
obj:=_obj;
node:=AllocMem(SizeOf(t_patch_node));
node^.vaddr:=vaddr;
node^.ptype:=ptype;
node^.stub :=stub;
p_inc_ref(stub);
TAILQ_INSERT_TAIL(@obj^.patchq,node,@node^.link);
end;
procedure free_patch_link(_obj:Pointer;node:p_patch_node);
var
obj:vm_object_t;
begin
obj:=_obj;
TAILQ_REMOVE(@obj^.patchq,node,@node^.link);
p_dec_ref(node^.stub);
FreeMem(node);
end;
function OFF_TO_IDX(x:Pointer):DWORD; inline;
begin
Result:=QWORD(x) shr PAGE_SHIFT;
end;
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
var
obj:vm_object_t;
entry,next:p_patch_node;
begin
obj:=_obj;
entry:=TAILQ_FIRST(@obj^.patchq);
while (entry<>nil) do
begin
next:=TAILQ_NEXT(entry,@entry^.link);
//
if ((start=0) or (OFF_TO_IDX(entry^.vaddr)>=start)) and
((__end=0) or (OFF_TO_IDX(entry^.vaddr)<=__end)) then
begin
free_patch_link(_obj,entry);
end;
//
entry:=next;
end;
end;
{
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]
@ -533,10 +456,32 @@ begin
Result:=-1;
end;
procedure _fast_syscall; assembler; nostackframe;
asm
mov %rax,%rax
jmp fast_syscall
procedure vm_add_syscall_patch(_obj,vaddr,addr_out:Pointer);
var
stub:p_stub_chunk;
jmpq64_trampoline:t_jmpq64_trampoline;
call32_trampoline:t_call32_trampoline;
delta:Int64;
begin
stub:=p_alloc(vaddr,SizeOf(t_jmpq64_trampoline));
delta:=Int64(@stub^.body)-(Int64(vaddr)+SizeOf(t_call32_trampoline));
Assert(delta<High(Integer),'vm_add_syscall_patch');
jmpq64_trampoline:=c_jmpq64_trampoline;
call32_trampoline:=c_call32_trampoline;
jmpq64_trampoline.addr:=QWORD(@fast_syscall);
call32_trampoline.addr:=Integer(delta);
p_jmpq64_trampoline(@stub^.body)^:=jmpq64_trampoline;
p_call32_trampoline(addr_out)^:=call32_trampoline;
md_cacheflush(@stub^.body,SizeOf(t_jmpq64_trampoline),ICACHE);
vm_add_patch_link(_obj,vaddr,pt_syscall,stub);
end;
procedure patcher_process_section(_obj,data,vaddr:Pointer;filesz:QWORD);
@ -559,36 +504,16 @@ var
Move(patch_table[i].C[1],addr^,patch_table[i].C[0]);
v:=vaddr+(Int64(addr)-Int64(data));
add_patch_link(_obj,v,ptype,nil);
vm_add_patch_link(_obj,v,ptype,nil);
end;
procedure do_patch_syscall(addr:PByte);
var
v:Pointer;
stub:p_stub_chunk;
jmpq64_trampoline:t_jmpq64_trampoline;
call32_trampoline:t_call32_trampoline;
d:Int64;
begin
v:=vaddr+(Int64(addr)-Int64(data));
stub:=p_alloc(v,SizeOf(t_jmpq64_trampoline));
d:=Int64(@stub^.body)-(Int64(v)+SizeOf(t_call32_trampoline));
Assert(d<High(Integer),'do_patch_syscall');
jmpq64_trampoline:=c_jmpq64_trampoline;
call32_trampoline:=c_call32_trampoline;
jmpq64_trampoline.addr:=QWORD(@_fast_syscall);
call32_trampoline.addr:=Integer(d);
p_jmpq64_trampoline(@stub^.body)^:=jmpq64_trampoline;
p_call32_trampoline(addr)^:=call32_trampoline;
add_patch_link(_obj,v,pt_syscall,stub);
vm_add_syscall_patch(_obj,v,addr);
end;
begin
@ -629,7 +554,7 @@ begin
end;
end else
begin
Writeln('patch with offset:',offset);
//Writeln('patch with offset:',offset);
end;
end;
34:

View File

@ -44,7 +44,8 @@ begin
((relro_addr + obj^.relro_size) < (where + size))
) then
begin
Exit(ENOEXEC);
//dont check with special callbacks
//Exit(ENOEXEC);
end;
Result:=0;

View File

@ -42,7 +42,7 @@ uses
var
chunk_alloc:TSTUB_HAMT64;
chunk_free :TAILQ_HEAD=(tqh_first:nil;tqh_last:@chunk_free .tqh_first);
chunk_free :TAILQ_HEAD=(tqh_first:nil;tqh_last:@chunk_free.tqh_first);
chunk_lock :Pointer=nil;
@ -169,7 +169,7 @@ begin
if (entry^.curr_size>=(size+SizeOf(stub_chunk))) then
begin
delta:=abs(Int64(vaddr)-Int64(@entry^.body));
if (delta<High(Integer)) then
if (vaddr=nil) or (delta<High(Integer)) then
begin
TAILQ_REMOVE(@chunk_free,entry,@entry^.link);
Exit(entry);

View File

@ -33,11 +33,10 @@ const
KERN_PROC_SDK_VERSION =36; //SDK version of the executable file
KERN_PROC_IDTABLE =37; //ID table information
KERN_PROC_SANITIZER =41; //kern_sanitizer (Sanitizing mode)
KERN_PROC_TEXT_SEGMENT=44; //kern_dynlib_get_libkernel_text_segment
//SYSCTL_HANDLER_ARGS oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req
type
@ -65,6 +64,7 @@ type
t_oid_handler=function(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
t_sysctl_oid=record
oid_name :PInteger;
oid_handler:t_oid_handler;
end;
@ -85,7 +85,8 @@ uses
vmparam,
kern_thr,
kern_sx,
md_arc4random;
md_arc4random,
md_proc;
var
sysctllock :t_sx;
@ -122,8 +123,9 @@ begin
Result:=req^.oldfunc(req,p,s);
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;func:Pointer):Integer; inline;
function SYSCTL_HANDLE(noid:p_sysctl_oid;name:PInteger;func:Pointer):Integer; inline;
begin
noid^.oid_name :=name+1;
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
@ -217,12 +219,102 @@ begin
Result:=SYSCTL_OUT(req,@data,len);
end;
const
//eLoadOptions
LOAD_OPTIONS_DEFAULT =$0000;
LOAD_OPTIONS_LOAD_SUSPENDED =$0001;
LOAD_OPTIONS_USE_SYSTEM_LIBRARY_VERIFICATION =$0002;
LOAD_OPTIONS_SLV_MODE_WARN =$0004;
LOAD_OPTIONS_ARG_STACK_SIZE =$0008;
LOAD_OPTIONS_FULL_DEBUG_REQUIRED =$0010;
//mmap_flags
//bit 1 -> is_big_app
//bit 2 -> first find addr is (1 shl 33) ->
// _sceKernelMapFlexibleMemory
// _sceKernelMapDirectMemory
// sceKernelMapDirectMemory2
//excp_flags
//bit 1 -> use in [libkernel_exception] ->
// -> sceKernelInstallExceptionHandler
// -> sceKernelRemoveExceptionHandler
// -> sceKernelAddGpuExceptionEvent
// -> sceKernelDeleteGpuExceptionEvent
// -> sceKernelBacktraceSelf
//bit 2 -> sys_mdbg_service
type
TCUSANAME=array[0..9] of AnsiChar;
PSCE_APP_ENV=^TSCE_APP_ENV;
TSCE_APP_ENV=packed record
AppId :Integer; //4
mmap_flags :Integer; //4
excp_flags :Integer; //4
AppType :Integer; //4 5?
CUSANAME :TCUSANAME; //10
debug_level:Byte; //1
slv_flags :Byte; //1 eLoadOptions
f_1c :Byte;
f_1d :Byte;
f_1e :Byte;
f_1f :Byte;
f_20 :QWORD;
f_28 :Integer;
f_2c :Integer;
f_30 :Integer;
f_34 :Integer;
f_38 :QWORD;
f_40 :QWORD;
end;
{$IF sizeof(TSCE_APP_ENV)<>72}{$STOP sizeof(TSCE_APP_ENV)<>72}{$ENDIF}
var
G_APPINFO:TSCE_APP_ENV;
function sysctl_kern_proc_appinfo(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
pid:Integer;
APPINFO:TSCE_APP_ENV;
begin
if (req^.oldlen > 72) then Exit(EINVAL);
pid:=PInteger(arg1)^;
if (pid<>g_pid) then Exit(EINVAL);
//sceSblACMgrIsSystemUcred()!=0 -> any proc
//sceSblACMgrIsSystemUcred()==0 -> cur proc
Result:=SYSCTL_OUT(req,@G_APPINFO,SizeOf(TSCE_APP_ENV));
if (Result=0) and (req^.newlen=SizeOf(TSCE_APP_ENV)) then
begin
Result:=SYSCTL_IN(req,@APPINFO,SizeOf(TSCE_APP_ENV));
if (Result=0) then
begin
G_APPINFO:=APPINFO;
end;
end;
end;
function sysctl_kern_proc(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
Writeln(StdErr,'sysctl_kern_proc:',name[0]);
case name[0] of
KERN_PROC_APPINFO:Result:=SYSCTL_HANDLE(noid,name,@sysctl_kern_proc_appinfo);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern_proc:',name[0]);
Assert(False);
end;
end;
end;
function sysctl_kern(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
@ -233,10 +325,11 @@ begin
case name[0] of
KERN_PROC:Result:=sysctl_kern_proc(name+1,namelen-1,noid,req);
KERN_ARND:Result:=SYSCTL_HANDLE(noid,@sysctl_kern_arandom);
KERN_ARND:Result:=SYSCTL_HANDLE(noid,name,@sysctl_kern_arandom);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern:',name[0]);
Assert(False);
end;
end;
end;
@ -253,7 +346,8 @@ begin
CTL_KERN:Result:=sysctl_kern(name+1,namelen-1,noid,req);
else
begin
Writeln(StdErr,'Unhandled sysctl_find_oid:',name[0]);
Writeln(StdErr,'Unhandled sysctl_root:',name[0]);
Assert(False);
end;
end;
end;
@ -264,6 +358,7 @@ function sysctl_root(oidp:p_sysctl_oid;
req :p_sysctl_req):Integer;
var
oid:t_sysctl_oid;
indx:Integer;
begin
oid:=Default(t_sysctl_oid);
@ -271,6 +366,12 @@ begin
if (Result<>0) then Exit;
if (oid.oid_handler=nil) then Exit(EINVAL);
if (oid.oid_name =nil) then Exit(EINVAL);
indx:=oid.oid_name-arg1;
arg1:=arg1 + indx;
arg2:=arg2 - indx;
//if ((oid.oid_kind and CTLTYPE)=CTLTYPE_NODE) then
//begin

View File

@ -209,6 +209,7 @@ type
sysc_e00:Pointer;
sym_zero:elf64_sym;
sym_nops:elf64_sym;
dyn_non_exist:Integer;
end;
@ -2200,7 +2201,7 @@ begin
Result:=nil;
err:=0;
fname:=ExtractFileName(path);
fname:=dynlib_basename(path);
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
@ -2239,6 +2240,8 @@ begin
fname:=ChangeFileExt(fname,'.prx');
if rtld_file_exists(pchar(fname)) then goto _do_load;
Writeln(StdErr,' prx module not found:',path);
err:=ENOENT;
Exit(nil);

View File

@ -605,6 +605,10 @@
<Filename Value="..\md\md_arc4random.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\vm\vm_patch_link.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -108,7 +108,7 @@ uses
vmparam,
vnode,
vfs_subr,
kern_patcher;
vm_patch_link;
function IDX_TO_OFF(x:DWORD):QWORD; inline;
begin

95
sys/vm/vm_patch_link.pas Normal file
View File

@ -0,0 +1,95 @@
unit vm_patch_link;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
kern_stub;
type
t_patch_type=(pt_fsbase,pt_gsbase,pt_syscall);
p_patch_node=^t_patch_node;
t_patch_node=record
link :TAILQ_ENTRY;
vaddr:Pointer;
ptype:t_patch_type;
stub :p_stub_chunk;
end;
procedure vm_add_patch_link(_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
implementation
uses
vmparam,
vm_object;
procedure vm_add_patch_link(_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
var
obj:vm_object_t;
node:p_patch_node;
begin
//Writeln('patch:vaddr=0x',HexStr(vaddr),' type:',ptype);
obj:=_obj;
node:=AllocMem(SizeOf(t_patch_node));
node^.vaddr:=vaddr;
node^.ptype:=ptype;
node^.stub :=stub;
p_inc_ref(stub);
VM_OBJECT_LOCK(obj);
TAILQ_INSERT_TAIL(@obj^.patchq,node,@node^.link);
VM_OBJECT_UNLOCK(obj);
end;
procedure vm_free_patch_link(_obj:Pointer;node:p_patch_node);
var
obj:vm_object_t;
begin
obj:=_obj;
TAILQ_REMOVE(@obj^.patchq,node,@node^.link);
p_dec_ref(node^.stub);
FreeMem(node);
end;
function OFF_TO_IDX(x:Pointer):DWORD; inline;
begin
Result:=QWORD(x) shr PAGE_SHIFT;
end;
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
var
obj:vm_object_t;
entry,next:p_patch_node;
begin
obj:=_obj;
VM_OBJECT_LOCK(obj);
entry:=TAILQ_FIRST(@obj^.patchq);
while (entry<>nil) do
begin
next:=TAILQ_NEXT(entry,@entry^.link);
//
if ((start=0) or (OFF_TO_IDX(entry^.vaddr)>=start)) and
((__end=0) or (OFF_TO_IDX(entry^.vaddr)<=__end)) then
begin
vm_free_patch_link(_obj,entry);
end;
//
entry:=next;
end;
VM_OBJECT_UNLOCK(obj);
end;
end.