FPPS4/sys/kern/kern_dynlib.pas

713 lines
16 KiB
Plaintext

unit kern_dynlib;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
sysutils,
mqueue,
kern_rtld,
subr_dynlib,
kern_dlsym,
kern_reloc,
kern_named_id;
const
SCE_DBG_MAX_NAME_LENGTH = 256;
SCE_DBG_MAX_SEGMENTS = 4;
SCE_DBG_NUM_FINGERPRINT = 20;
type
SceKernelModuleSegmentInfo=packed record
addr:Pointer;
size:DWORD;
prot:Integer; //PF_
end;
SceDynlibName=array[0..SCE_DBG_MAX_NAME_LENGTH-1] of AnsiChar;
pSceKernelModuleInfo=^SceKernelModuleInfo;
SceKernelModuleInfo=packed record
size :QWORD; //Size of this structure
name :SceDynlibName; //name.prx
segmentInfo :array[0..SCE_DBG_MAX_SEGMENTS-1] of SceKernelModuleSegmentInfo;
segmentCount:DWORD;
fingerprint :array[0..SCE_DBG_NUM_FINGERPRINT-1] of Byte;
end;
{$IF sizeof(SceKernelModuleInfo)<>352}{$STOP sizeof(SceKernelModuleInfo)<>352}{$ENDIF}
pSceKernelModuleInfoEx=^SceKernelModuleInfoEx;
SceKernelModuleInfoEx=packed record
st_size :QWORD; //424
name :SceDynlibName; //name.prx
id :Integer;
tls_index :DWORD;
tls_init_addr :Pointer;
tls_init_size :DWORD;
tls_size :DWORD;
tls_offset :DWORD;
tls_align :DWORD;
init_proc_addr :Pointer;
fini_proc_addr :Pointer;
reserved1 :QWORD;
reserved2 :QWORD;
eh_frame_hdr_addr:Pointer;
eh_frame_addr :Pointer;
eh_frame_hdr_size:DWORD;
eh_frame_size :DWORD;
segments :array[0..SCE_DBG_MAX_SEGMENTS-1] of SceKernelModuleSegmentInfo;
segment_count :DWORD;
ref_count :DWORD;
end;
{$IF sizeof(SceKernelModuleInfoEx)<>424}{$STOP sizeof(SceKernelModuleInfoEx)<>424}{$ENDIF}
pSceModuleInfoForUnwind=^SceModuleInfoForUnwind;
SceModuleInfoForUnwind=packed record
st_size :qword; //304
name :SceDynlibName; //name.prx
eh_frame_hdr_addr:Pointer;
eh_frame_addr :Pointer;
eh_frame_size :qword;
seg0_addr :Pointer;
seg0_size :qword;
end;
function sys_dynlib_dlsym(handle:Integer;symbol:pchar;addrp:ppointer):Integer;
function sys_dynlib_process_needed_and_relocate():Integer;
function sys_dynlib_do_copy_relocations():Integer;
function sys_dynlib_load_prx(moduleFileName:pchar;flags:DWORD;pRes:PInteger;unused:Pointer):Integer;
function sys_dynlib_unload_prx(handle:Integer;args:QWORD;argp:Pointer):Integer;
function sys_dynlib_get_info(handle:Integer;info:Pointer):Integer;
function sys_dynlib_get_info2(handle:Integer;info:Pointer):Integer;
function sys_dynlib_get_info_ex(handle,flags:Integer;info:Pointer):Integer;
function sys_dynlib_get_info_for_libdbg(handle:Integer;info:Pointer):Integer;
function sys_dynlib_get_list(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
function sys_dynlib_get_list2(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
function sys_dynlib_get_list_for_libdbg(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
function sys_dynlib_get_obj_member(handle:Integer;num:Byte;pout:PPointer):Integer;
function sys_dynlib_get_proc_param(pout:PPointer;psize:PQWORD):Integer;
function sys_dl_get_info(pid,handle:Integer;pout:PPointer):Integer;
function sys_dl_get_list(pid:Integer;pArray:PInteger;numArray:Integer;pActualNum:PInteger):Integer;
function sys_dl_get_metadata(pid,handle:Integer;pout:Pointer;size:Integer;pactual_size:PInteger):Integer;
implementation
uses
errno,
systm,
vm,
kern_proc,
kern_budget;
function not_dynamic:Boolean; inline;
begin
Result:=True;
if (dynlibs_info.libprogram=nil) then Exit;
if (dynlibs_info.libprogram^.rel_data=nil) then Exit;
Result:=False;
end;
function sys_dynlib_dlsym(handle:Integer;symbol:pchar;addrp:ppointer):Integer;
label
_exit;
var
obj:p_lib_info;
flags:Integer;
ptr:Pointer;
fsym:array[0..2560-1] of char;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_dlsym:','this is not dynamic linked program.');
Exit(EPERM);
end;
Result:=copyinstr(symbol,@fsym,sizeof(fsym),nil);
if (Result<>0) then Exit;
Writeln('sys_dynlib_dlsym:',fsym);
dynlibs_lock;
obj:=find_obj_by_handle(handle);
if (obj=nil) then
begin
Result:=ESRCH;
goto _exit;
end;
flags:=0;
if (StrLComp(@fsym,'BaOKcng8g88',Length('BaOKcng8g88'))=0) or
(StrLComp(@fsym,'KpDMrPHvt3Q',Length('KpDMrPHvt3Q'))=0) then
begin
flags:=SYMLOOK_BASE64;
end;
ptr:=do_dlsym(obj,@fsym,nil,flags);
if (ptr=nil) then
begin
Result:=ESRCH;
goto _exit;
end;
Result:=copyout(@ptr,addrp,SizeOf(Pointer));
_exit:
dynlibs_unlock;
end;
function sys_dynlib_process_needed_and_relocate():Integer;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_process_needed_and_relocate:','this is not dynamic linked program.');
Exit(EPERM);
end;
dynlibs_lock;
Result:=dynlib_load_needed_shared_objects();
if (Result=0) then
begin
Result:=dynlib_load_relocate();
end;
if (Result=0) then
begin
Result:=dmem_process_relocated();
end;
dynlibs_unlock;
end;
function sys_dynlib_do_copy_relocations():Integer;
begin
dynlibs_lock;
Result:=check_copy_relocations(dynlibs_info.libprogram);
dynlibs_unlock;
end;
function sys_dynlib_load_prx(moduleFileName:pchar;flags:DWORD;pRes:PInteger;unused:Pointer):Integer;
label
_exit;
var
len:ptruint;
fname:array[0..1024-1] of char;
obj:p_lib_info;
key:Integer;
allocs:Boolean;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_load_prx:','this is not dynamic linked program.');
Exit(EPERM);
end;
//0x10000 //priv libs?
//0x20000 //set jmpslots_done?
//0x40000 //set not_get_proc?
if ((flags and $fff8ffff)<>0) then Exit(EINVAL);
len:=0;
Result:=copyinstr(moduleFileName,@fname,sizeof(fname),@len);
if (Result<>0) then Exit;
Writeln('sys_dynlib_load_prx("',fname,'",0x',HexStr(flags,6),')');
dynlibs_lock;
obj:=nil;
Result:=load_prx(@fname,flags or ord(p_proc.p_budget_ptype=PTYPE_BIG_APP),obj);
if (Result=0) then
begin
allocs:=(obj^.id<=0);
if (obj^.ref_count < 2) then
begin
if not alloc_obj_id(obj) then
begin
unload_prx(obj);
Result:=EAGAIN;
goto _exit;
end;
end;
key:=obj^.id;
Result:=copyout(@key,pRes,SizeOf(Integer));
if (Result<>0) then
begin
if allocs then
begin
free_obj_id(obj^.id);
obj^.id:=0;
end;
unload_prx(obj);
Result:=EFAULT;
end;
end;
_exit:
dynlibs_unlock;
//dynlib_notify_event(td,resid,0x40);
end;
function sys_dynlib_unload_prx(handle:Integer;args:QWORD;argp:Pointer):Integer;
var
obj:p_lib_info;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_unload_prx:','this is not dynamic linked program.');
Exit(EPERM);
end;
//Writeln('sys_dynlib_unload_prx:',handle);
dynlibs_lock;
obj:=find_obj_id(handle);
if (obj=nil) then
begin
Result:=ESRCH;
end else
begin
id_acqure(obj);
//
Result:=unload_prx(obj);
//
id_release(obj); //<-id_acqure
end;
dynlibs_unlock;
end;
function kern_dynlib_get_info(handle,flags:Integer;dst:pSceKernelModuleInfo):Integer;
var
obj:p_lib_info;
lib_path:pchar;
lib_name:pchar;
begin
Result:=ESRCH;
dynlibs_lock;
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
if (obj^.id=handle) then
begin
dst^:=Default(SceKernelModuleInfo);
if ((flags and 1)=0) and (obj^.rtld_flags.is_system<>0) then
begin
Result:=EPERM;
Break;
end;
lib_path:=obj^.lib_path;
lib_name:=dynlib_basename(lib_path);
strlcopy(dst^.name,lib_name,SCE_DBG_MAX_NAME_LENGTH);
//if not is_webkit then
begin
dst^.segmentCount:=2;
dst^.segmentInfo[0].addr:=obj^.map_base;
dst^.segmentInfo[0].size:=obj^.text_size;
dst^.segmentInfo[0].prot:=VM_PROT_READ or VM_PROT_EXECUTE;
dst^.segmentInfo[1].addr:=obj^.data_addr;
dst^.segmentInfo[1].size:=obj^.data_size;
dst^.segmentInfo[1].prot:=VM_PROT_RW;
if (obj^.relro_addr<>nil) and (obj^.relro_size<>0) then
begin
dst^.segmentInfo[2].addr:=obj^.relro_addr;
dst^.segmentInfo[2].size:=obj^.relro_size;
dst^.segmentInfo[2].prot:=VM_PROT_READ;
dst^.segmentCount:=3;
end;
end;
Move(obj^.fingerprint,dst^.fingerprint,SCE_DBG_NUM_FINGERPRINT);
Result:=0;
Break;
end;
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
dynlibs_unlock;
end;
function sys_dynlib_get_info(handle:Integer;info:Pointer):Integer;
var
size:QWORD;
dst:SceKernelModuleInfo;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_get_info:','this is not dynamic linked program.');
Exit(EPERM);
end;
size:=0;
Result:=copyin(info,@size,SizeOf(QWORD));
if (Result<>0) then
begin
Exit(EFAULT);
end;
if (size<>SizeOf(SceKernelModuleInfo)) then
begin
Exit(EINVAL);
end;
Result:=kern_dynlib_get_info(handle,1,@dst);
if (Result<>0) then Exit;
Result:=copyout(@dst,info,SizeOf(SceKernelModuleInfo));
end;
function sys_dynlib_get_info2(handle:Integer;info:Pointer):Integer;
var
size:QWORD;
dst:SceKernelModuleInfo;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_get_info2:','this is not dynamic linked program.');
Exit(EPERM);
end;
size:=0;
Result:=copyin(info,@size,SizeOf(QWORD));
if (Result<>0) then
begin
Exit(EFAULT);
end;
if (size<>SizeOf(SceKernelModuleInfo)) then
begin
Exit(EINVAL);
end;
Result:=kern_dynlib_get_info(handle,0,@dst);
if (Result<>0) then Exit;
Result:=copyout(@dst,info,SizeOf(SceKernelModuleInfo));
end;
function kern_dynlib_get_info_ex(handle,flags:Integer;dst:pSceKernelModuleInfoEx):Integer;
var
obj:p_lib_info;
lib_path:pchar;
lib_name:pchar;
tls_index:Integer;
begin
Result:=ESRCH;
dynlibs_lock;
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
if (obj^.id=handle) then
begin
dst^:=Default(SceKernelModuleInfoEx);
lib_path:=obj^.lib_path;
lib_name:=dynlib_basename(lib_path);
strlcopy(dst^.name,lib_name,SCE_DBG_MAX_NAME_LENGTH);
dst^.id:=obj^.id;
tls_index:=WORD(obj^.tls_index);
dst^.tls_index:=tls_index;
if ((flags and 1)<>0) then
begin
tls_index:=(
(obj^.rtld_flags.is_system or (obj^.rtld_flags.mainprog shl 1)) shl 16
) or tls_index;
dst^.tls_index:=tls_index;
end;
Writeln(' get_info_ex :',obj^.lib_path);
Writeln(' obj.id :',obj^.id);
Writeln(' tls_flags :0x',HexStr(tls_index shr 16,4));
Writeln(' tls_index :0x',HexStr(tls_index,4));
Writeln(' tls_init_addr:0x',HexStr(QWORD(obj^.tls_init_addr),11));
Writeln(' tls_init_size:0x',HexStr(obj^.tls_init_size,8));
Writeln(' tls_size :0x',HexStr(obj^.tls_size ,8));
Writeln(' tls_offset :0x',HexStr(obj^.tls_offset ,8));
Writeln(' tls_align :0x',HexStr(obj^.tls_align ,8));
if ((flags and 2)<>0) then
begin
if (obj^.rtld_flags.is_system<>0) {or (is_webkit)} then
begin
FillChar(dst^.name,SCE_DBG_MAX_NAME_LENGTH,0);
end;
end;
dst^.tls_init_addr :=obj^.tls_init_addr;
dst^.tls_init_size :=DWORD(obj^.tls_init_size);
dst^.tls_size :=DWORD(obj^.tls_size);
dst^.tls_offset :=DWORD(obj^.tls_offset);
dst^.tls_align :=DWORD(obj^.tls_align);
dst^.reserved1 :=0;
dst^.reserved2 :=0;
dst^.eh_frame_hdr_addr:=obj^.eh_frame_hdr_addr;
dst^.eh_frame_addr :=obj^.eh_frame_addr;
dst^.eh_frame_hdr_size:=DWORD(obj^.eh_frame_hdr_size);
dst^.eh_frame_size :=DWORD(obj^.eh_frame_size);
dst^.ref_count :=obj^.ref_count;
//if not webkit then
begin
if (obj^.rtld_flags.not_get_proc=0) then
begin
dst^.init_proc_addr:=obj^.init_proc_addr;
dst^.fini_proc_addr:=obj^.fini_proc_addr;
end;
dst^.segments[0].addr:=obj^.map_base;
dst^.segments[0].size:=obj^.text_size;
dst^.segments[0].prot:=VM_PROT_READ or VM_PROT_EXECUTE;
dst^.segments[1].addr:=obj^.data_addr;
dst^.segments[1].size:=obj^.data_size;
dst^.segments[1].prot:=VM_PROT_RW;
dst^.segment_count:=2;
end;
Result:=0;
Break;
end;
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
dynlibs_unlock;
end;
function sys_dynlib_get_info_ex(handle,flags:Integer;info:Pointer):Integer;
var
size:QWORD;
dst:SceKernelModuleInfoEx;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_get_info_ex:','this is not dynamic linked program.');
Exit(EPERM);
end;
size:=0;
Result:=copyin(info,@size,SizeOf(QWORD));
if (Result<>0) then
begin
Exit(EFAULT);
end;
if (size<>SizeOf(SceKernelModuleInfoEx)) then
begin
Exit(EINVAL);
end;
Result:=kern_dynlib_get_info_ex(handle,flags,@dst);
if (Result<>0) then Exit;
Result:=copyout(@dst,info,SizeOf(SceKernelModuleInfoEx));
end;
function sys_dynlib_get_info_for_libdbg(handle:Integer;info:Pointer):Integer;
begin
Exit(EPERM); //sceKernelIsDevelopmentMode
end;
function copyout_module_handle_list(pArray:PInteger;numArray:QWORD;flags:DWORD;pActualNum:PQWORD):Integer;
var
i,w,count:QWORD;
src:PInteger;
obj:p_lib_info;
begin
if not_dynamic then
begin
Writeln(StdErr,'copyout_module_handle_list:','this is not dynamic linked program.');
Exit(EPERM);
end;
dynlibs_lock;
i:=0;
w:=0;
count:=dynlibs_info.obj_count;
if (((flags and 1)<>0) and (count > numArray)) then
begin
dynlibs_unlock;
Exit(ENOMEM);
end;
src:=AllocMem(count*SizeOf(Integer));
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) and (i<count) do
begin
if ((flags and 1)<>0) or (obj^.rtld_flags.is_system=0) then
begin
if (w>=numArray) then
begin
dynlibs_unlock;
FreeMem(src);
Exit(ENOMEM);
end;
src[w]:=obj^.id;
Inc(w);
end;
//
Inc(i);
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
dynlibs_unlock;
if (i<>count) and ((flags and 1)<>0) then
begin
Writeln(StdErr,'copyout_module_handle_list:','WARNING: num<>dp^.obj_count');
end;
Result:=copyout(src,pArray,w*SizeOf(Integer));
if (Result=0) then
begin
Result:=copyout(@w,pActualNum,8);
end;
FreeMem(src);
end;
function sys_dynlib_get_list(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
begin
Result:=copyout_module_handle_list(pArray,numArray,1,pActualNum);
end;
function sys_dynlib_get_list2(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
begin
Result:=copyout_module_handle_list(pArray,numArray,0,pActualNum);
end;
function sys_dynlib_get_list_for_libdbg(pArray:PInteger;numArray:QWORD;pActualNum:PQWORD):Integer;
begin
Exit(EPERM); //sceKernelIsDevelopmentMode
end;
function sys_dynlib_get_obj_member(handle:Integer;num:Byte;pout:PPointer):Integer;
var
obj:p_lib_info;
dst:Pointer;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_get_obj_member:','this is not dynamic linked program.');
Exit(EPERM);
end;
dynlibs_lock;
Result:=ESRCH;
obj:=TAILQ_FIRST(@dynlibs_info.obj_list);
while (obj<>nil) do
begin
if (obj^.id=handle) then
begin
dst:=nil;
case num of
1:if (obj^.rtld_flags.not_get_proc=0) then
begin
dst:=obj^.init_proc_addr;
end;
2:if (obj^.rtld_flags.not_get_proc=0) then
begin
dst:=obj^.fini_proc_addr;
end;
3:begin
dst:=obj^.eh_frame_hdr_addr;
end;
4:begin
dst:=obj^.eh_frame_addr;
end;
7:begin
dst:=obj^.tls_init_addr;
end;
8:begin
dst:=obj^.module_param;
end;
else
begin
dynlibs_unlock;
Exit(EINVAL);
end;
end;
Result:=copyout(@dst,pout,SizeOf(Pointer));
Break;
end;
//
obj:=TAILQ_NEXT(obj,@obj^.link);
end;
dynlibs_unlock;
end;
function sys_dynlib_get_proc_param(pout:PPointer;psize:PQWORD):Integer;
begin
if not_dynamic then
begin
Writeln(StdErr,'sys_dynlib_get_proc_param:','this is not dynamic linked program.');
Exit(EPERM);
end;
Result:=copyout(@dynlibs_info.proc_param_addr,pout,SizeOf(Pointer));
if (Result=0) then
begin
Result:=copyout(@dynlibs_info.proc_param_size,psize,SizeOf(QWORD));
end;
end;
function sys_dl_get_info(pid,handle:Integer;pout:PPointer):Integer;
begin
Exit(EPERM); //sceSblACMgrIsDebuggerProcess || sceSblACMgrIsCoredumpProcess || sceSblACMgrIsSyscoreProcess
end;
function sys_dl_get_list(pid:Integer;pArray:PInteger;numArray:Integer;pActualNum:PInteger):Integer;
begin
Exit(EPERM); //sceSblACMgrIsDebuggerProcess || sceSblACMgrIsCoredumpProcess || sceSblACMgrIsSyscoreProcess
end;
function sys_dl_get_metadata(pid,handle:Integer;pout:Pointer;size:Integer;pactual_size:PInteger):Integer;
begin
//sce_comment_addr
//sce_comment_size
Exit(EPERM); //sceSblACMgrIsDebuggerProcess || sceSblACMgrIsCoredumpProcess || sceSblACMgrIsSyscoreProcess
end;
end.