feat: typing
This commit is contained in:
+8
-1
@@ -9,7 +9,13 @@ export default defineConfig([
|
||||
files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
|
||||
plugins: { js },
|
||||
extends: ['js/recommended'],
|
||||
languageOptions: { globals: globals.browser },
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
jsmaf: 'readonly',
|
||||
log: 'readonly',
|
||||
}
|
||||
},
|
||||
},
|
||||
{ files: ['**/*.js'], languageOptions: { sourceType: 'script' } },
|
||||
tseslint.configs.recommended,
|
||||
@@ -27,6 +33,7 @@ export default defineConfig([
|
||||
'no-unused-expressions': 'off',
|
||||
'no-fallthrough': 'off',
|
||||
'no-new-native-nonconstructor': 'off', // we use our own BigInt
|
||||
'no-extend-native': 'off', // we extend native for better usage
|
||||
|
||||
// TS duplicates
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
|
||||
+34
-37
@@ -443,8 +443,11 @@ DataView.prototype.setBigInt = function (byteOffset, value, littleEndian) {
|
||||
this.setUint32(byteOffset + 4, value.hi(), littleEndian)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {struct}
|
||||
*/
|
||||
var struct = {
|
||||
register: function (name, fields) {
|
||||
create: function (name, fields) {
|
||||
if (name in this) {
|
||||
throw new Error(`${name} already registered in struct !!`)
|
||||
}
|
||||
@@ -457,8 +460,6 @@ var struct = {
|
||||
}
|
||||
}
|
||||
|
||||
this[name] = cls
|
||||
|
||||
cls.tname = name
|
||||
cls.sizeof = sizeof
|
||||
cls.fields = fields
|
||||
@@ -466,15 +467,8 @@ var struct = {
|
||||
for (var info of infos) {
|
||||
struct.define_property(cls, info)
|
||||
}
|
||||
},
|
||||
unregister: function (name) {
|
||||
if (!(name in this)) {
|
||||
throw new Error(`${name} not registered in struct !!`)
|
||||
}
|
||||
|
||||
delete this[name]
|
||||
|
||||
return true
|
||||
return cls
|
||||
},
|
||||
parse: function (fields) {
|
||||
var infos = []
|
||||
@@ -663,7 +657,7 @@ var struct = {
|
||||
}
|
||||
}
|
||||
|
||||
struct.register('NotificationRequest', [
|
||||
var NotificationRequest = struct.create('NotificationRequest', [
|
||||
{ type: 'Int32', name: 'type' },
|
||||
{ type: 'Int32', name: 'reqId' },
|
||||
{ type: 'Int32', name: 'priority' },
|
||||
@@ -804,6 +798,9 @@ master_addr = new BigInt(master[5], master[4])
|
||||
debug(`master_addr: ${master_addr}`)
|
||||
log('Achieved ARW !!')
|
||||
|
||||
/**
|
||||
* @type {mem}
|
||||
*/
|
||||
var mem = {
|
||||
allocs: new Map(),
|
||||
read8: function (addr) {
|
||||
@@ -875,6 +872,9 @@ var mem = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {utils}
|
||||
*/
|
||||
var utils = {
|
||||
base_addr: function (func_addr) {
|
||||
var module_info_addr = mem.malloc(0x130)
|
||||
@@ -892,9 +892,9 @@ var utils = {
|
||||
return base_addr
|
||||
},
|
||||
notify: function (msg) {
|
||||
var notify_addr = mem.malloc(struct.NotificationRequest.sizeof)
|
||||
var notify_addr = mem.malloc(NotificationRequest.sizeof)
|
||||
|
||||
var notify = new struct.NotificationRequest(notify_addr)
|
||||
var notify = new NotificationRequest(notify_addr)
|
||||
|
||||
for (var i = 0; i < msg.length; i++) {
|
||||
notify.message[i] = msg.charCodeAt(i) & 0xFF
|
||||
@@ -902,13 +902,13 @@ var utils = {
|
||||
|
||||
notify.message[msg.length] = 0
|
||||
|
||||
var fd = fn.open('/dev/notification0', 1, 0)
|
||||
var fd = open('/dev/notification0', 1, 0)
|
||||
if (fd.lt(0)) {
|
||||
throw new Error('Unable to open /dev/notification0 !!')
|
||||
}
|
||||
|
||||
fn.write(fd, notify.addr, struct.NotificationRequest.sizeof)
|
||||
fn.close(fd)
|
||||
write(fd, notify.addr, NotificationRequest.sizeof)
|
||||
close(fd)
|
||||
|
||||
mem.free(notify_addr)
|
||||
},
|
||||
@@ -1019,6 +1019,9 @@ var gadgets = {
|
||||
PUSH_RAX_POP_RBP_RET: jsc_addr.add(0x4E82B9)
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {rop}
|
||||
*/
|
||||
var rop = {
|
||||
idx: 0,
|
||||
base: 0x2500,
|
||||
@@ -1132,8 +1135,12 @@ var rop = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {fn}
|
||||
*/
|
||||
var fn = {
|
||||
register: function (input, name, ret) {
|
||||
// args is just for typing, not used
|
||||
create: function (input, _args, ret) {
|
||||
if (name in this) {
|
||||
throw new Error(`${name} already registered in fn !!`)
|
||||
}
|
||||
@@ -1243,23 +1250,13 @@ var fn = {
|
||||
|
||||
Object.defineProperty(f, 'addr', { value: addr })
|
||||
|
||||
fn[name] = f
|
||||
},
|
||||
unregister (name) {
|
||||
if (!(name in this)) {
|
||||
log(`${name} not registered in fn !!`)
|
||||
return false
|
||||
}
|
||||
|
||||
delete fn[name]
|
||||
|
||||
return true
|
||||
return f
|
||||
}
|
||||
}
|
||||
|
||||
rop.init()
|
||||
|
||||
fn.register(libc_addr.add(0x5F0), 'sceKernelGetModuleInfoForUnwind', 'bigint')
|
||||
var sceKernelGetModuleInfoForUnwind = fn.create(libc_addr.add(0x5F0), ['bigint'], 'bigint')
|
||||
|
||||
var libkernel_addr = utils.base_addr(_error_addr)
|
||||
|
||||
@@ -1314,12 +1311,12 @@ syscalls.init(libkernel_addr)
|
||||
|
||||
debug(`Found ${syscalls.map.size} syscalls`)
|
||||
|
||||
fn.register(_error_addr, '_error', 'bigint')
|
||||
fn.register(strerror_addr, 'strerror', 'string')
|
||||
fn.register(0x14, 'getpid', 'bigint')
|
||||
fn.register(0x29, 'dup', 'bigint')
|
||||
fn.register(0x4, 'write', 'bigint')
|
||||
fn.register(0x5, 'open', 'bigint')
|
||||
fn.register(0x6, 'close', 'bigint')
|
||||
var _error = fn.create(_error_addr, [], 'bigint')
|
||||
var strerror = fn.create(strerror_addr, ['bigint'], 'string')
|
||||
var getpid = fn.create(0x14, [], 'bigint')
|
||||
var dup = fn.create(0x29, ['bigint'], 'bigint')
|
||||
var write = fn.create(0x4, ['bigint', 'bigint', 'number'], 'bigint')
|
||||
var open = fn.create(0x5, ['string', 'number', 'number'], 'bigint')
|
||||
var close = fn.create(0x6, ['bigint'], 'bigint')
|
||||
|
||||
utils.notify('UwU')
|
||||
|
||||
+2
-1
@@ -23,5 +23,6 @@
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts", "**/*.js", "**/*.js.aes"],
|
||||
}
|
||||
|
||||
Vendored
+189
@@ -0,0 +1,189 @@
|
||||
declare namespace vue {
|
||||
declare class BigInt {
|
||||
buf: ArrayBuffer
|
||||
i8: Int8Array
|
||||
u8: Uint8Array
|
||||
i16: Int16Array
|
||||
u16: Uint16Array
|
||||
i32: Int32Array
|
||||
u32: Uint32Array
|
||||
f32: Float32Array
|
||||
f64: Float64Array
|
||||
|
||||
static readonly Zero: BigInt
|
||||
static readonly One: BigInt
|
||||
static readonly TYPE_MAP: {
|
||||
Int8Array: 'i8',
|
||||
Uint8Array: 'u8',
|
||||
Int16Array: 'i16',
|
||||
Uint16Array: 'u16',
|
||||
Int32Array: 'i32',
|
||||
Uint32Array: 'u32',
|
||||
Float32Array: 'f32',
|
||||
Float64Array: 'f64',
|
||||
}
|
||||
|
||||
constructor ()
|
||||
constructor (value: number | string | BigInt | ArrayLike<number>)
|
||||
constructor (hi: number, lo: number)
|
||||
|
||||
toString (): string
|
||||
endian (): void
|
||||
lo (): number
|
||||
hi (): number
|
||||
d (): number
|
||||
jsv (): BigInt
|
||||
cmp (val: BigInt): -1 | 0 | 1
|
||||
eq (val: BigInt): boolean
|
||||
neq (val: BigInt): boolean
|
||||
gt (val: BigInt): boolean
|
||||
gte (val: BigInt): boolean
|
||||
lt (val: BigInt): boolean
|
||||
lte (val: BigInt): boolean
|
||||
add (val: BigInt): BigInt
|
||||
sub (val: BigInt): BigInt
|
||||
mul (val: BigInt): BigInt
|
||||
divmod (val: BigInt): { q: BigInt, r: BigInt }
|
||||
div (val: BigInt): BigInt
|
||||
mod (val: BigInt): BigInt
|
||||
xor (val: BigInt): BigInt
|
||||
and (val: BigInt): BigInt
|
||||
or (val: BigInt): BigInt
|
||||
neg (): BigInt
|
||||
shl (count: number): BigInt
|
||||
shr (count: number): BigInt
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface DataView {
|
||||
getBigInt (byteOffset: number, littleEndian?: boolean): vue.BigInt
|
||||
setBigInt (byteOffset: number, value: vue.BigInt, littleEndian?: boolean): void
|
||||
}
|
||||
|
||||
function log (msg: string): void
|
||||
function debug (msg: string): void
|
||||
}
|
||||
|
||||
type NonPointerTypes = `${'Int' | 'Uint'}${8 | 16 | 32 | 64}`
|
||||
type PointerTypes = `${NonPointerTypes}*`
|
||||
|
||||
type StructName<T> = T extends `${infer Name}[${string}]` ? Name : T
|
||||
type StructCount<T> = T extends { count: infer C extends number } ? C :
|
||||
T extends { name: `${string}[${infer C extends number}]` } ? C :
|
||||
1
|
||||
|
||||
interface BaseStructField {
|
||||
size?: number
|
||||
offset?: number
|
||||
}
|
||||
|
||||
interface PointerStructField extends BaseStructField {
|
||||
name: string
|
||||
type: PointerTypes
|
||||
pointer?: true
|
||||
count?: never
|
||||
}
|
||||
|
||||
interface NonPointerStructFieldWithCountName extends BaseStructField {
|
||||
name: `${string}[${number}]`
|
||||
type: NonPointerTypes
|
||||
pointer?: false
|
||||
count?: number
|
||||
}
|
||||
|
||||
interface NonPointerStructFieldWithCount extends BaseStructField {
|
||||
name: name
|
||||
type: NonPointerTypes
|
||||
pointer?: false
|
||||
count: number
|
||||
}
|
||||
|
||||
interface NonPointerStructField extends BaseStructField {
|
||||
name: name
|
||||
type: NonPointerTypes
|
||||
pointer?: false
|
||||
count?: 1
|
||||
}
|
||||
|
||||
type StructField = PointerStructField | NonPointerStructFieldWithCount | NonPointerStructFieldWithCountName | NonPointerStructField
|
||||
|
||||
type StructReturnType<const T extends StructField> =
|
||||
StructCount<T> extends (1 | undefined) ? (
|
||||
T['pointer'] extends true ? vue.BigInt :
|
||||
T['type'] extends 'Int64' ? vue.BigInt :
|
||||
T['type'] extends 'Uint64' ? vue.BigInt :
|
||||
number
|
||||
) : (
|
||||
T['type'] extends 'Int8' ? Int8Array :
|
||||
T['type'] extends 'Uint8' ? Uint8Array :
|
||||
T['type'] extends 'Int16' ? Int16Array :
|
||||
T['type'] extends 'Uint16' ? Uint16Array :
|
||||
T['type'] extends 'Int32' ? Int32Array :
|
||||
T['type'] extends 'Uint32' ? Uint32Array :
|
||||
T['type'] extends 'Int64' ? Int32Array :
|
||||
T['type'] extends 'Uint64' ? Uint32Array :
|
||||
never
|
||||
)
|
||||
|
||||
type StructInstance<const T extends readonly StructField[]> = {
|
||||
[K in T[number] as StructName<K['name']>]: StructReturnType<K>
|
||||
} & {
|
||||
addr: vue.BigInt
|
||||
}
|
||||
|
||||
interface StructConstructor<const Name extends string, const T extends readonly StructField[]> {
|
||||
new (addr: vue.BigInt): StructInstance<T>
|
||||
|
||||
readonly tname: Name
|
||||
readonly sizeof: number
|
||||
readonly fields: T
|
||||
}
|
||||
|
||||
declare type struct = {
|
||||
create<const Name extends string, const T extends StructField[]>(name: Name, fields: T): StructConstructor<Name, T>
|
||||
}
|
||||
|
||||
declare type mem = {
|
||||
allocs: Map<vue.BigInt, ArrayBufferLike>
|
||||
read8 (addr: vue.BigInt): vue.BigInt
|
||||
read4 (addr: vue.BigInt): vue.BigInt
|
||||
write8 (addr: vue.BigInt, value: vue.BigInt): void
|
||||
write4 (addr: vue.BigInt, value: vue.BigInt): void
|
||||
write1 (addr: vue.BigInt, value: vue.BigInt): void
|
||||
addrof (obj: unknown): vue.BigInt
|
||||
fakeobj (addr: vue.BigInt): unknown
|
||||
malloc (size: number): vue.BigInt
|
||||
free (addr: vue.BigInt): void
|
||||
free_all (): void
|
||||
}
|
||||
|
||||
declare type utils = {
|
||||
base_addr (func_addr: vue.BigInt): vue.BigInt
|
||||
notify (msg: string): void
|
||||
str (addr: vue.BigInt): string
|
||||
cstr (str: string): vue.BigInt
|
||||
get_backing (view: ArrayBufferLike): vue.BigInt
|
||||
set_backing (view: ArrayBufferLike, addr: vue.BigInt): void
|
||||
}
|
||||
|
||||
declare type rop = {
|
||||
init (): void
|
||||
free (): void
|
||||
reset (): void
|
||||
push (val: vue.BigInt): void
|
||||
execute (insts: vue.BigInt[], store_addr: vue.BigInt, store_size: number): void
|
||||
fake_builtin (addr: vue.BigInt): (useless1: number, useless2: number, useless3: number, addr: vue.BigInt) => void
|
||||
store (insts: vue.BigInt[], addr: vue.BigInt, index: number): void
|
||||
load (insts: vue.BigInt[], addr: vue.BigInt, index: number): void
|
||||
}
|
||||
|
||||
type ArgTypeToRealType<T> = T extends 'bigint' ? vue.BigInt :
|
||||
T extends 'boolean' ? boolean :
|
||||
T extends 'number' ? number :
|
||||
T extends 'string' ? string :
|
||||
never
|
||||
|
||||
declare type fn = {
|
||||
create <const Args extends ('bigint' | 'number' | 'boolean' | 'string')[], Return extends ('bigint' | 'boolean' | 'string')>(addr: vue.BigInt | number, args: Args, ret: Return): (...func_args: { [K in keyof Args]: ArgTypeToRealType<Args[K]> }) => ArgTypeToRealType<Return>
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
declare function include (path: string): unknown
|
||||
|
||||
declare namespace jsmaf {
|
||||
declare class Text {
|
||||
x: number
|
||||
y: number
|
||||
background: string
|
||||
url: string
|
||||
text: string
|
||||
|
||||
constructor ()
|
||||
}
|
||||
|
||||
declare class WebSocketServer {
|
||||
port: number
|
||||
onmessage: (clientID: number, data: string) => void
|
||||
|
||||
constructor ()
|
||||
broadcast (data: string): void
|
||||
}
|
||||
|
||||
declare namespace root {
|
||||
declare const children: Text[]
|
||||
}
|
||||
|
||||
declare function eval (code: string): unknown
|
||||
}
|
||||
Reference in New Issue
Block a user