├── .eslintrc.js ├── .gitignore ├── README.md ├── addr_map ├── map.ts ├── wcc.map └── wcsc.map ├── agent ├── cpp │ ├── std_deque.ts │ ├── std_map.ts │ ├── std_string.ts │ ├── std_stringstream.ts │ └── std_vector.ts ├── hook │ ├── index.ts │ ├── nt │ │ ├── db-linux.ts │ │ ├── db-win32.ts │ │ ├── host-win32.ts │ │ ├── index.ts │ │ ├── log-win32.ts │ │ ├── msf.ts │ │ ├── oidb │ │ │ ├── oidb.ts │ │ │ ├── param-parse.ts │ │ │ └── process-start.ts │ │ ├── sql-linux.ts │ │ └── sqlite3_step.ts │ └── utils │ │ ├── addr.ts │ │ └── file.ts ├── index.ts ├── logger.ts └── utils │ ├── log.ts │ └── map.ts ├── hook.js ├── hook.py ├── nt.js ├── nt.py ├── package.json ├── pcqq_get_key.py ├── pnpm-lock.yaml ├── tools ├── gen_map.js ├── gen_transittable.js ├── https.js ├── server.crt ├── server.key └── str.js ├── tsconfig.json └── uilts.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'typescript-eslint-parser', 3 | env: { 4 | browser: true, 5 | es6: true, 6 | }, 7 | extends: 'airbnb-base', 8 | globals: { 9 | Atomics: 'readonly', 10 | SharedArrayBuffer: 'readonly', 11 | }, 12 | parserOptions: { 13 | ecmaVersion: 2018, 14 | sourceType: 'module', 15 | }, 16 | rules: { 17 | //import/extensions起的作用 18 | 'import/extensions': [ 19 | 2, // 0 = off, 1 = warn, 2 = error 20 | 'ignorePackages', 21 | { 22 | ts: 'never', 23 | }, 24 | ], 25 | }, 26 | settings: { 27 | //import/resolver起的作用 28 | 'import/resolver': { 29 | alias: { 30 | map: [ 31 | ['@', './src'], 32 | ], 33 | extensions: ['.ts'], 34 | }, 35 | }, 36 | }, 37 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /_agent.js 2 | /node_modules 3 | output*.log 4 | res 5 | tmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NT HOOK 2 | 3 | ## 说明 4 | 5 | 用于HOOK NTQQ的一些函数,打出日志。 6 | 7 | 建议针对较新的某一个版本进行操作,否则地址变更会比较痛苦。 8 | 9 | ## 使用 10 | 11 | 1. `pnpm install` 12 | 2. `pnpm run watch` 13 | 3. `pnpm run hook-py` 14 | 15 | ### Development workflow 16 | 17 | To continuously recompile on change, keep this running in a terminal: 18 | 19 | ```sh 20 | $ pnpm run watch 21 | ``` 22 | 23 | And use an editor like Visual Studio Code for code completion and instant 24 | type-checking feedback. 25 | -------------------------------------------------------------------------------- /agent/cpp/std_deque.ts: -------------------------------------------------------------------------------- 1 | 2 | // std::deque of MingW 120 (2013) 3 | 4 | import { StdString } from "./std_string.js"; 5 | 6 | /* 7 | 8 | _Map_pointer _M_map; 9 | size_t _M_map_size; 10 | iterator _M_start; 11 | iterator _M_finish; 12 | 13 | std::string size 24 14 | */ 15 | 16 | export default class StdDeque { 17 | private addr 18 | private valueSize 19 | private introspectElement 20 | constructor(addr: NativePointer, valueSize: number, introspectElement: (p: NativePointer) => any) { 21 | this.addr = addr; 22 | this.valueSize = valueSize; 23 | this.introspectElement = introspectElement; 24 | } 25 | 26 | get DEQUESIZ() { 27 | return this.valueSize <= 1 ? 16 28 | : this.valueSize <= 2 ? 8 29 | : this.valueSize <= 4 ? 4 30 | : this.valueSize <= 8 ? 2 31 | : 1; 32 | } 33 | 34 | get containerProxy() { 35 | return this.addr.readPointer(); 36 | } 37 | 38 | get map() { 39 | return this.addr.add(Process.pointerSize).readPointer(); 40 | } 41 | 42 | get mapsize() { 43 | return this.addr.add(Process.pointerSize * 1).readPointer(); 44 | } 45 | 46 | get iteratorStart() { 47 | return this.addr.add(Process.pointerSize * 2).readPointer(); 48 | } 49 | 50 | get iteratorFinish() { 51 | return this.addr.add(Process.pointerSize * 6).readPointer(); 52 | } 53 | 54 | get contents() { 55 | const r: any[] = []; 56 | const iteratorStart = this.iteratorStart.toInt32(); 57 | const iteratorFinish = this.iteratorFinish.toInt32(); 58 | for(let i = iteratorStart; i < iteratorFinish; i += this.valueSize) { 59 | const elemAddr = new NativePointer(i) 60 | let elem; 61 | if(this.introspectElement) { 62 | elem = this.introspectElement(elemAddr); 63 | } else { 64 | elem = elemAddr.readByteArray(this.valueSize); 65 | } 66 | r.push(elem); 67 | } 68 | return r; 69 | } 70 | 71 | toString() { 72 | return "deque@" + this.addr 73 | + "{ map=" + this.map 74 | + ", offset=" + this.iteratorStart 75 | + ", size=" + this.iteratorFinish 76 | + ", contents: " + this.contents + "}"; 77 | } 78 | 79 | toJSON() { 80 | return { 81 | type: 'std::deque', 82 | contents: this.contents, 83 | } 84 | } 85 | } 86 | 87 | export const stdDequeStdStringParse = (p: NativePointer) => { 88 | /* 89 | D0 B5 ED 00 10 92 ED 00 E0(起点) EE ED 00 08 00 00 00 90 | 58 B1 ED 00(iteratorStart) 58 B1 ED 00 50 B3 ED 00 EC EE ED 00 91 | 70 B1 ED 00(iteratorFinish) 58 B1 ED 00 50 B3 ED 00 EC EE ED 00 92 | */ 93 | return new StdDeque(p, 24, (elePoint) => { 94 | return new StdString(elePoint).toString() || '' 95 | }) 96 | } -------------------------------------------------------------------------------- /agent/cpp/std_map.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 44 FC 97 00 00 00 00 00 30(起始) 6E D4 76 00 00 00 00 3 | 78 C9 E1 00(根元素) F8 A1 E1 00(元素) 68 E0 E1 00(元素) 08 00 00 00(个数) 4 | 00 00 E1 00 00 00 00 00 00 00 00 00 74 FC 97 00 5 | 74 FC 97 00 00 00 00 00 00 00 00 00 A0 E5 53 00 6 | 20 E5 53 00 E0 EE 53 00 40 E9 53 00 00 00 00 00 7 | */ 8 | /** 9 | 01 00 00 00 5C FC 97 00(父地址) C0 BE DE 00(左子地址) 98 CD DE 00(右子地址) 10 | F8 CE DE 00 2B 00 00 00(key) 2B 00 00 00 0D F0 AD BA 11 | 0D F0 AD BA 0D F0 AD BA D8 B6 DE 00 DA 00 00 00(value) 12 | */ 13 | 14 | import { StdString } from "./std_string.js" 15 | import { stdVectorStringParse, stdVectorStringParseJSON } from "./std_vector.js" 16 | 17 | interface StdMapOption { 18 | inspectElement: (p: NativePointer) => any 19 | } 20 | const BUF_SIZE = 16 21 | export default class StdMap { 22 | private addr: NativePointer 23 | private options: StdMapOption 24 | constructor(addr: NativePointer, options: StdMapOption) { 25 | this.addr = addr 26 | this.options = options 27 | } 28 | get size() { 29 | return this.addr.add(20).readU32() 30 | } 31 | /** 32 | * 中序遍历 33 | * @param ptr 节点地址 34 | * @returns 35 | */ 36 | inorderTraverse(ptr: NativePointer) { 37 | const left = ptr.add(8) 38 | const right = left.add(4) 39 | let result: string = '' 40 | if (left.readU32() > 0) 41 | result += this.inorderTraverse(left.readPointer()) 42 | result += this.options.inspectElement(ptr) 43 | if (right.readU32() > 0) 44 | result += this.inorderTraverse(right.readPointer()) 45 | if (result.endsWith(',')) 46 | result = result.substring(0, result.length - 1) 47 | 48 | return result 49 | } 50 | inorderTraverseJSON(ptr: NativePointer) { 51 | const left = ptr.add(8) 52 | const right = left.add(4) 53 | let result: any[] = [] 54 | if (left.readU32() > 0) 55 | result.push(...this.inorderTraverseJSON(left.readPointer())) 56 | result.push(this.options.inspectElement(ptr)) 57 | if (right.readU32() > 0) 58 | result.push(...this.inorderTraverseJSON(right.readPointer())) 59 | 60 | return result 61 | } 62 | toJSON() { 63 | const result: Record = { 64 | type: 'std::map', 65 | size: this.size, 66 | data: [] 67 | } 68 | const startPtr = this.addr.add(8) 69 | if (startPtr.readU32() > 0) { 70 | result.data = this.inorderTraverseJSON(startPtr.readPointer()) 71 | } 72 | return result 73 | } 74 | toString() { 75 | const startPtr = this.addr.add(8) 76 | let data = `{ size:${this.size}, content:[` 77 | if (startPtr.readU32() > 0) { 78 | data = this.inorderTraverse(startPtr.readPointer()) 79 | } 80 | data += ']' 81 | return `StdMap{${data}}` 82 | } 83 | } 84 | 85 | export const stdMapString2StringParse = (p: NativePointer) => { 86 | return new StdMap(p, { 87 | inspectElement(ptr) { 88 | // console.log('data:', ptr.readU64().toString(16)) 89 | const keyPtr = ptr.add(16) 90 | const valuePtr = keyPtr.add(24) 91 | // console.log('key:', keyPtr) 92 | // console.log('value:', valuePtr) 93 | const result = { 94 | key: '', 95 | value: '', 96 | } 97 | if (keyPtr.readU32() > 0) 98 | result.key = new StdString(keyPtr).toString() || '' 99 | if (valuePtr.readU32() > 0) 100 | result.value = new StdString(valuePtr).toString() || '' 101 | return JSON.stringify(result, null, 4) + ',\n' 102 | } 103 | }).toString() 104 | } 105 | 106 | export const stdMapString2StringParseJSON = (p: NativePointer) => { 107 | return new StdMap(p, { 108 | inspectElement(ptr) { 109 | // console.log('data:', ptr.readU64().toString(16)) 110 | const keyPtr = ptr.add(16) 111 | const valuePtr = keyPtr.add(24) 112 | // console.log('key:', keyPtr) 113 | // console.log('value:', valuePtr) 114 | const result = { 115 | key: '', 116 | value: '', 117 | } 118 | if (keyPtr.readU32() > 0) 119 | result.key = new StdString(keyPtr).toString() || '' 120 | if (valuePtr.readU32() > 0) 121 | result.value = new StdString(valuePtr).toString() || '' 122 | return result 123 | } 124 | }).toJSON() 125 | } 126 | export const stdMapString2IntParse = (p: NativePointer) => { 127 | return new StdMap(p, { 128 | inspectElement(ptr) { 129 | // console.log('data:', ptr.readU64().toString(16)) 130 | const keyPtr = ptr.add(16) 131 | const valuePtr = keyPtr.add(24) 132 | // console.log('key:', keyPtr) 133 | // console.log('value:', valuePtr) 134 | const result = { 135 | key: '', 136 | value: 0, 137 | } 138 | if (keyPtr.readU32() > 0) 139 | result.key = new StdString(keyPtr).toString() || '' 140 | if (valuePtr.readU32() > 0) 141 | result.value = valuePtr.readU32() 142 | return result 143 | } 144 | }).toJSON() 145 | } 146 | 147 | /** 148 | * map> 149 | * @param p 150 | * @returns 151 | */ 152 | export const stdMapString2VectorStringParse = (p: NativePointer) => { 153 | return new StdMap(p, { 154 | inspectElement(ptr) { 155 | // console.log('data:', ptr.readU64().toString(16)) 156 | const keyPtr = ptr.add(16) 157 | const valuePtr = keyPtr.add(24) 158 | // console.log('key:', keyPtr) 159 | // console.log('value:', valuePtr) 160 | const result = { 161 | key: '', 162 | value: '', 163 | } 164 | if (keyPtr.readU32() > 0) 165 | result.key = new StdString(keyPtr).toString() || '' 166 | if (valuePtr.readU32() > 0) 167 | result.value = stdVectorStringParse(valuePtr) 168 | return JSON.stringify(result, null, 4) + ',\n' 169 | } 170 | }).toString() 171 | } 172 | 173 | /** 174 | * map> 175 | * @param p 176 | * @returns 177 | */ 178 | export const stdMapString2VectorStringParseJSON = (p: NativePointer) => { 179 | return new StdMap(p, { 180 | inspectElement(ptr) { 181 | // console.log('data:', ptr.readU64().toString(16)) 182 | const keyPtr = ptr.add(16) 183 | const valuePtr = keyPtr.add(24) 184 | // console.log('key:', keyPtr) 185 | // console.log('value:', valuePtr) 186 | const result = { 187 | key: '', 188 | value: {}, 189 | } 190 | if (keyPtr.readU32() > 0) 191 | result.key = new StdString(keyPtr).toString() || '' 192 | if (valuePtr.readU32() > 0) 193 | result.value = stdVectorStringParseJSON(valuePtr) 194 | return result 195 | } 196 | }).toJSON() 197 | } -------------------------------------------------------------------------------- /agent/cpp/std_string.ts: -------------------------------------------------------------------------------- 1 | 2 | // std::string of MSVC 120 (2013) 3 | 4 | /* 5 | union 6 | { 7 | value_type _Buf[_BUF_SIZE]; 8 | pointer _Ptr; 9 | }; 10 | size_type _Mysize; // current length of string 11 | size_type _Myres; // current storage reserved for string 12 | */ 13 | /** 14 | * 总24字节 15 | * 前8个字节 16 | * 00 00 00 00, 00 00 00 00, 00 00 00 00 17 | * 前四个字节地址,四个字节长度,四个字节容量 18 | */ 19 | export const STD_STRING_BUF_SIZE = 4; 20 | 21 | export class StdString { 22 | private addr 23 | constructor(addr: NativePointer) { 24 | this.addr = addr; 25 | } 26 | 27 | get bufAddr() { 28 | return this.addr.readPointer(); 29 | // if(this.reservedSize.compare(16) > 0) { 30 | // return this.addr.readPointer(); 31 | // } else { 32 | // return this.addr; 33 | // } 34 | } 35 | 36 | get size() { 37 | return this.addr.add(4).readU32(); 38 | } 39 | 40 | get reservedSize() { 41 | return this.addr.add(STD_STRING_BUF_SIZE).add(Process.pointerSize).readU32(); 42 | } 43 | 44 | toString() { 45 | const size = this.size; 46 | if(size == 0) { 47 | return ""; 48 | } 49 | const addr = this.bufAddr 50 | try { 51 | return addr.readUtf8String(size); 52 | } catch (error) { 53 | return addr.readUtf8String(size - 1); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /agent/cpp/std_stringstream.ts: -------------------------------------------------------------------------------- 1 | 2 | // std::string of MSVC 120 (2013) 3 | 4 | /* 5 | union 6 | { 7 | value_type _Buf[_BUF_SIZE]; 8 | pointer _Ptr; 9 | }; 10 | size_type _Mysize; // current length of string 11 | size_type _Myres; // current storage reserved for string 12 | */ 13 | /** 14 | * 15 | */ 16 | 17 | export class StdStringStream { 18 | private addr: NativePointer 19 | constructor(addr: NativePointer) { 20 | this.addr = addr; 21 | } 22 | get start() { 23 | return this.addr.add(20).readPointer() 24 | } 25 | get end() { 26 | return this.addr.add(24).readPointer() 27 | } 28 | toJSON() { 29 | return { 30 | addr: [ 31 | this.addr.readPointer(), 32 | this.addr.add(4).readPointer(), 33 | this.addr.add(8).readPointer(), 34 | this.addr.add(12).readPointer(), 35 | this.addr.add(16).readPointer(), 36 | this.addr.add(20).readPointer(), 37 | ], 38 | start: this.start, 39 | end: this.end, 40 | length: this.end.sub(this.start).toUInt32(), 41 | content: this.start.readUtf8String(this.end.sub(this.start).toUInt32()), 42 | } 43 | } 44 | toString() { 45 | return this.start.readUtf8String(this.end.sub(this.start).toUInt32()); 46 | } 47 | } -------------------------------------------------------------------------------- /agent/cpp/std_vector.ts: -------------------------------------------------------------------------------- 1 | 2 | // std::vector of MSVC 120 (2013) 3 | 4 | import { StdString } from "./std_string.js" 5 | 6 | /* 7 | pointer _Myfirst; // pointer to beginning of array 8 | pointer _Mylast; // pointer to current end of sequence 9 | pointer _Myend; // pointer to end of array 10 | */ 11 | 12 | export interface StdVectorOption { 13 | elementSize: number 14 | introspectElement: (p: NativePointer) => any 15 | } 16 | 17 | export default class StdVector { 18 | private addr 19 | private elementSize 20 | private introspectElement 21 | constructor(addr: NativePointer, options: StdVectorOption) { 22 | this.addr = addr; 23 | this.elementSize = options.elementSize ? options.elementSize : Process.pointerSize; 24 | this.introspectElement = options.introspectElement; 25 | // console.log('init ptr:', addr) 26 | } 27 | 28 | get myfirst() { 29 | // console.log('myfirst:', this.addr) 30 | return this.addr.readPointer(); 31 | } 32 | 33 | get mylast() { 34 | // console.log('mylast') 35 | return this.addr.add(Process.pointerSize).readPointer(); 36 | } 37 | 38 | get myend() { 39 | // console.log('myend') 40 | return this.addr.add(2 * Process.pointerSize).readPointer(); 41 | } 42 | 43 | countBetween(begin: NativePointer, end: NativePointer) { 44 | if(begin.isNull()) { 45 | return 0; 46 | } 47 | const delta = end.sub(begin); 48 | return delta.toInt32() / this.elementSize; 49 | } 50 | 51 | get size() { 52 | return this.countBetween(this.myfirst, this.mylast); 53 | } 54 | 55 | get capacity() { 56 | return this.countBetween(this.myfirst, this.myend); 57 | } 58 | toJSON() { 59 | const result: Record = { 60 | type: 'std::vector', 61 | first: this.myfirst, 62 | last: this.mylast, 63 | end: this.myend, 64 | size: this.size, 65 | capacity: this.capacity, 66 | data: [] 67 | } 68 | const first = this.myfirst 69 | if(!first.isNull()) { 70 | const last = this.mylast; 71 | for(let p = first; p.compare(last) < 0; p = p.add(this.elementSize)) { 72 | result.data.push(this.introspectElement(p)); 73 | } 74 | } 75 | return result 76 | } 77 | toString() { 78 | let r = "std::vector(" + this.myfirst + ", " + this.mylast + ", " + this.myend + ")"; 79 | r += "{ size: " + this.size + ", capacity: " + this.capacity; 80 | if(this.introspectElement) { 81 | r += ", content: ["; 82 | const first = this.myfirst 83 | if(!first.isNull()) { 84 | const last = this.mylast; 85 | for(let p = first; p.compare(last) < 0; p = p.add(this.elementSize)) { 86 | if(p.compare(first) > 0) { 87 | r += ", "; 88 | } 89 | r += this.introspectElement(p); 90 | } 91 | } 92 | r += "]"; 93 | } 94 | r += " }"; 95 | return r; 96 | } 97 | } 98 | 99 | export const stdVectorStringParse = (p: NativePointer) => { 100 | return new StdVector(p, { 101 | introspectElement(p) { 102 | return new StdString(p).toString() || 'empty' 103 | }, 104 | elementSize: 24, 105 | }).toString() 106 | } 107 | export const stdVectorStringParseJSON = (p: NativePointer) => { 108 | return new StdVector(p, { 109 | introspectElement(p) { 110 | return new StdString(p).toString() || 'empty' 111 | }, 112 | elementSize: 24, 113 | }).toJSON() 114 | } -------------------------------------------------------------------------------- /agent/hook/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import BaseAddr from "./utils/addr.js"; 3 | import { hookNt as hookNt } from "./nt/index.js"; 4 | 5 | export const hook = (baseAddr: BaseAddr) => { 6 | // hookCPP(baseAddr) 7 | hookNt(baseAddr) 8 | // hookWcc(baseAddr) 9 | // hookWcsc(baseAddr) 10 | // hookWXSS(baseAddr) 11 | // hookNight(baseAddr) 12 | } -------------------------------------------------------------------------------- /agent/hook/nt/db-linux.ts: -------------------------------------------------------------------------------- 1 | import { StdString } from "../../cpp/std_string.js"; 2 | import BaseAddr from "../utils/addr.js"; 3 | 4 | export const hookDBLinux = (baseAddr: BaseAddr) => { 5 | { 6 | const target = 'db info' 7 | const targetAddr = baseAddr.resolveAddress('0x053D2280') 8 | if (targetAddr != null) { 9 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 10 | 11 | // When function is called, print out its parameters 12 | /* 13 | 以下内容演示了 14 | 1. 怎么提取 printf 的第一个参数的字符串 15 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 16 | 其他API 用法 17 | https://frida.re/docs/javascript-api/ 18 | */ 19 | onEnter: function (args) { 20 | try { 21 | console.log(`${target} - onEnter`); 22 | console.log('[+] Called targetAddr:' + targetAddr); 23 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 24 | // console.log('arg0:', readStdString(args[0])) 25 | const a1 = args[0] 26 | const a2 = args[1] 27 | const a3 = args[2] 28 | const a4 = args[3] 29 | console.log('a1:', a1) 30 | console.log('a1:', a1.readPointer()) 31 | 32 | console.log('a2:', a2) 33 | console.log('a2:', a2.readUtf8String(16)) 34 | 35 | console.log('a3:', a3) 36 | // console.log('a3:', a3.readUtf8String(16)) 37 | 38 | // console.log('a4:', a4) 39 | // console.log('a4:', a4.toInt32()) 40 | } 41 | catch (error) { 42 | console.log('error:', error) 43 | } 44 | 45 | /* 46 | dumpAddr('Input', args[0], args[3].toInt32()); 47 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 48 | this.outsize = args[2].toInt32(); 49 | */ 50 | }, 51 | 52 | // When function is finished 53 | onLeave: function (retval) { 54 | /* 55 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 56 | console.log('[+] Returned from SomeFunc: ' + retval); 57 | */ 58 | // console.log('retval:', new StdString(retval).toString()) 59 | console.log(`${target} - onLeave\n\n`); 60 | } 61 | }); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /agent/hook/nt/db-win32.ts: -------------------------------------------------------------------------------- 1 | import { StdString } from "../../cpp/std_string.js"; 2 | import BaseAddr from "../utils/addr.js"; 3 | 4 | export const hookDBWin32 = (baseAddr: BaseAddr) => { 5 | { 6 | const target = 'db info' 7 | const targetAddr = baseAddr.resolveAddress('0x0324CC00') 8 | if (targetAddr != null) { 9 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 10 | 11 | // When function is called, print out its parameters 12 | /* 13 | 以下内容演示了 14 | 1. 怎么提取 printf 的第一个参数的字符串 15 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 16 | 其他API 用法 17 | https://frida.re/docs/javascript-api/ 18 | */ 19 | onEnter: function (args) { 20 | try { 21 | console.log(`${target} - onEnter`); 22 | console.log('[+] Called targetAddr:' + targetAddr); 23 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 24 | // console.log('arg0:', readStdString(args[0])) 25 | const a1 = args[0] 26 | const a2 = args[1] 27 | const a3 = args[2] 28 | const a4 = args[3] 29 | console.log('a1:', a1) 30 | console.log('a1:', a1.readPointer()) 31 | 32 | console.log('a2:', a2) 33 | // console.log('a2:', a2.readUtf8String()) 34 | 35 | console.log('a3:', a3) 36 | console.log('a3:', a3.readUtf8String(16)) 37 | 38 | console.log('a4:', a4) 39 | console.log('a4:', a4.toInt32()) 40 | } 41 | catch (error) { 42 | console.log('error:', error) 43 | } 44 | 45 | /* 46 | dumpAddr('Input', args[0], args[3].toInt32()); 47 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 48 | this.outsize = args[2].toInt32(); 49 | */ 50 | }, 51 | 52 | // When function is finished 53 | onLeave: function (retval) { 54 | /* 55 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 56 | console.log('[+] Returned from SomeFunc: ' + retval); 57 | */ 58 | // console.log('retval:', new StdString(retval).toString()) 59 | console.log(`${target} - onLeave\n\n`); 60 | } 61 | }); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /agent/hook/nt/host-win32.ts: -------------------------------------------------------------------------------- 1 | import { StdString } from "../../cpp/std_string.js"; 2 | import BaseAddr from "../utils/addr.js"; 3 | 4 | export const hookHostsWin32 = (baseAddr: BaseAddr) => { 5 | { 6 | /** 7 | * 搜索 DebugGetIPByDomain 8 | * hook 该函数 9 | */ 10 | const target = 'hosts info' 11 | const targetAddr = baseAddr.resolveAddress('0x014F7BB0') 12 | if (targetAddr != null) { 13 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 14 | 15 | // When function is called, print out its parameters 16 | /* 17 | 以下内容演示了 18 | 1. 怎么提取 printf 的第一个参数的字符串 19 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 20 | 其他API 用法 21 | https://frida.re/docs/javascript-api/ 22 | */ 23 | onEnter: function (args) { 24 | try { 25 | console.log(`${target} - onEnter`); 26 | console.log('[+] Called targetAddr:' + targetAddr); 27 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 28 | // console.log('arg0:', readStdString(args[0])) 29 | const a1 = args[0] 30 | const a2 = args[1] 31 | const a3 = args[2] 32 | const a4 = args[3] 33 | console.log('a1:', a1) 34 | console.log('desc:', a1.readUtf8String()) 35 | 36 | console.log('a2:', a2) 37 | const domain = a2.readUtf8String() 38 | console.log('domain:', domain) 39 | console.log('length:', a2.readByteArray(32)) 40 | 41 | console.log('a3:', a3) 42 | console.log('type:', a3) 43 | 44 | console.log('a4:', a4) 45 | console.log('ips:', a4.readByteArray(64)) 46 | const start = a4.readPointer() 47 | const end = a4.add(8).readPointer() 48 | const len = end.sub(start).toInt32() / 40 49 | console.log('ip length:', len) 50 | if (domain == 'gchat.qpic.cn'){ 51 | for (let i = 0; i < len; i++) { 52 | const cur = start.add(40 * i) 53 | const ip = '127.0.0.1' 54 | // cur.writeUtf8String(ip) 55 | // cur.add(16).writeInt(ip.length) 56 | console.log(cur.readByteArray(40)) 57 | } 58 | } 59 | } 60 | catch (error) { 61 | console.log('error:', error) 62 | } 63 | 64 | /* 65 | dumpAddr('Input', args[0], args[3].toInt32()); 66 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 67 | this.outsize = args[2].toInt32(); 68 | */ 69 | }, 70 | 71 | // When function is finished 72 | onLeave: function (retval) { 73 | /* 74 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 75 | console.log('[+] Returned from SomeFunc: ' + retval); 76 | */ 77 | // console.log('retval:', new StdString(retval).toString()) 78 | console.log('ret:', retval) 79 | console.log(`${target} - onLeave\n\n`); 80 | } 81 | }); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /agent/hook/nt/index.ts: -------------------------------------------------------------------------------- 1 | import BaseAddr from "../utils/addr.js" 2 | import { hookLog } from "./log-win32.js" 3 | import { hookDBLinux } from "./db-linux.js" 4 | import { hookDBWin32 } from "./db-win32.js" 5 | import { hookSql } from "./sql-linux.js" 6 | import { hookHostsWin32 } from "./host-win32.js" 7 | import { hookOIDB } from "./oidb/oidb.js" 8 | import { hookMSF } from "./msf.js" 9 | import { hookSqlite3Step } from "./sqlite3_step.js" 10 | 11 | export const hookNt = (baseAddr: BaseAddr) => { 12 | hookLog(baseAddr) 13 | // hookHostsWin32(baseAddr) 14 | // hookDBLinux(baseAddr) 15 | // hookSql(baseAddr) 16 | // hookOIDB(baseAddr) 17 | hookMSF(baseAddr) 18 | // hookSqlite3Step(baseAddr) 19 | } -------------------------------------------------------------------------------- /agent/hook/nt/log-win32.ts: -------------------------------------------------------------------------------- 1 | import { useLogger } from "../../utils/log.js"; 2 | import { StdString } from "../../cpp/std_string.js"; 3 | import BaseAddr from "../utils/addr.js"; 4 | 5 | class VSprintf { 6 | private format: string 7 | private argList: NativePointer 8 | constructor(format: string, argList: NativePointer) 9 | { 10 | this.argList = argList 11 | this.format = format 12 | } 13 | toString() 14 | { 15 | const handle = [ 16 | { 17 | exp: 'd', 18 | handle: (argIndex: number) => { 19 | const arg = this.argList.add(argIndex * 8) 20 | return arg.readInt() 21 | } 22 | }, 23 | { 24 | exp: '02d', 25 | handle: (argIndex: number) => { 26 | const arg = this.argList.add(argIndex * 8) 27 | return arg.readInt() 28 | } 29 | }, 30 | { 31 | exp: '05d', 32 | handle: (argIndex: number) => { 33 | const arg = this.argList.add(argIndex * 8) 34 | return arg.readInt() 35 | } 36 | }, 37 | { 38 | exp: 'lld', 39 | handle: (argIndex: number) => { 40 | const arg = this.argList.add(argIndex * 8) 41 | return arg.readLong() 42 | } 43 | }, 44 | { 45 | exp: '+.1f', 46 | handle: (argIndex: number) => { 47 | const arg = this.argList.add(argIndex * 8) 48 | return arg.readFloat() 49 | } 50 | }, 51 | { 52 | exp: 's', 53 | handle: (argIndex: number) => { 54 | const arg = this.argList.add(argIndex * 8) 55 | return arg.readPointer().readUtf8String() 56 | } 57 | }, 58 | ] 59 | let result = '' 60 | let argIndex = 0 61 | for(let i=0; i < this.format.length; i++) 62 | { 63 | if (this.format[i] === '%') 64 | { 65 | // 表达式 66 | const subFormat = this.format.substring(i + 1) 67 | const h = handle.find(e => subFormat.startsWith(e.exp)) 68 | if (h) 69 | { 70 | result += h.handle(argIndex) 71 | i += h.exp.length 72 | } 73 | argIndex++ 74 | } 75 | else 76 | { 77 | // 非表达式 78 | result += this.format[i] 79 | } 80 | } 81 | return result 82 | } 83 | } 84 | 85 | export const hookLog = (baseAddr: BaseAddr) => { 86 | { 87 | const targetAddr = baseAddr.resolveAddress('0x035BC858') 88 | if (targetAddr != null) { 89 | const log = useLogger('vsprintf') 90 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 91 | 92 | // When function is called, print out its parameters 93 | /* 94 | 以下内容演示了 95 | 1. 怎么提取 printf 的第一个参数的字符串 96 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 97 | 其他API 用法 98 | https://frida.re/docs/javascript-api/ 99 | */ 100 | onEnter: function (args) { 101 | try { 102 | log.info(`onEnter`); 103 | log.info('[+] Called targetAddr:' + targetAddr); 104 | const format = args[3].readUtf8String() 105 | if (format && !format.startsWith('%d-%02d-%02d')) 106 | { 107 | log.info('write target:', args[0]) 108 | args[0] = ptr('1') 109 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 110 | log.info(args[2].toInt32()) 111 | log.info(args[3].readUtf8String()) 112 | log.info(args[5].readByteArray(16)) 113 | 114 | const printf = new VSprintf(format, args[5]) 115 | log.info(printf.toString()) 116 | } 117 | } 118 | catch (error) { 119 | log.info('error:', error) 120 | } 121 | 122 | /* 123 | dumpAddr('Input', args[0], args[3].toInt32()); 124 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 125 | this.outsize = args[2].toInt32(); 126 | */ 127 | }, 128 | 129 | // When function is finished 130 | onLeave: function (retval) { 131 | /* 132 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 133 | log.info('[+] Returned from SomeFunc: ' + retval); 134 | */ 135 | log.info('retval:', retval) 136 | log.info(`onLeave\n\n`); 137 | } 138 | }); 139 | } 140 | } 141 | { 142 | const targetAddr = baseAddr.resolveAddress('0x035BCAAC') 143 | if (targetAddr != null) { 144 | const log = useLogger('vsprintf_s') 145 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 146 | 147 | // When function is called, print out its parameters 148 | /* 149 | 以下内容演示了 150 | 1. 怎么提取 printf 的第一个参数的字符串 151 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 152 | 其他API 用法 153 | https://frida.re/docs/javascript-api/ 154 | */ 155 | onEnter: function (args) { 156 | try { 157 | log.info(`onEnter`); 158 | log.info('[+] Called targetAddr:' + targetAddr); 159 | const format = args[3].readUtf8String() 160 | if (format && !format.startsWith('%d-%02d-%02d')) 161 | { 162 | log.info('write target:', args[0]) 163 | // args[0] = new NativePointer(0x1) 164 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 165 | log.info(args[2].toInt32()) 166 | log.info(args[3].readUtf8String()) 167 | log.info(args[5].readByteArray(16)) 168 | 169 | const printf = new VSprintf(format, args[5]) 170 | log.info(printf.toString()) 171 | } 172 | } 173 | catch (error) { 174 | log.info('error:', error) 175 | } 176 | 177 | /* 178 | dumpAddr('Input', args[0], args[3].toInt32()); 179 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 180 | this.outsize = args[2].toInt32(); 181 | */ 182 | }, 183 | 184 | // When function is finished 185 | onLeave: function (retval) { 186 | /* 187 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 188 | log.info('[+] Returned from SomeFunc: ' + retval); 189 | */ 190 | log.info('retval:', retval) 191 | log.info(`onLeave\n\n`); 192 | } 193 | }); 194 | } 195 | } 196 | { 197 | const targetAddr = baseAddr.resolveAddress('0x035BCBC0') 198 | if (targetAddr != null) { 199 | const log = useLogger('vsnprintf_s') 200 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 201 | 202 | // When function is called, print out its parameters 203 | /* 204 | 以下内容演示了 205 | 1. 怎么提取 printf 的第一个参数的字符串 206 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 207 | 其他API 用法 208 | https://frida.re/docs/javascript-api/ 209 | */ 210 | onEnter: function (args) { 211 | try { 212 | log.info(`onEnter`); 213 | log.info('[+] Called targetAddr:' + targetAddr); 214 | const format = args[3].readUtf8String() 215 | if (format && !format.startsWith('%d-%02d-%02d')) 216 | { 217 | log.info('write target:', args[0]) 218 | // args[0] = new NativePointer(0x1) 219 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 220 | log.info(args[2].toInt32()) 221 | log.info(args[3].readUtf8String()) 222 | log.info(args[5].readByteArray(16)) 223 | 224 | const printf = new VSprintf(format, args[5]) 225 | log.info(printf.toString()) 226 | } 227 | } 228 | catch (error) { 229 | log.info('error:', error) 230 | } 231 | 232 | /* 233 | dumpAddr('Input', args[0], args[3].toInt32()); 234 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 235 | this.outsize = args[2].toInt32(); 236 | */ 237 | }, 238 | 239 | // When function is finished 240 | onLeave: function (retval) { 241 | /* 242 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 243 | log.info('[+] Returned from SomeFunc: ' + retval); 244 | */ 245 | log.info('retval:', retval) 246 | log.info(`onLeave\n\n`); 247 | } 248 | }); 249 | } 250 | } 251 | { 252 | const targetAddr = baseAddr.resolveAddress('0x035BC1E8') 253 | if (targetAddr != null) { 254 | const log = useLogger('vswprintf') 255 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 256 | 257 | // When function is called, print out its parameters 258 | /* 259 | 以下内容演示了 260 | 1. 怎么提取 printf 的第一个参数的字符串 261 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 262 | 其他API 用法 263 | https://frida.re/docs/javascript-api/ 264 | */ 265 | onEnter: function (args) { 266 | try { 267 | log.info(`onEnter`); 268 | log.info('[+] Called targetAddr:' + targetAddr); 269 | const format = args[3].readUtf8String() 270 | if (format && !format.startsWith('%d-%02d-%02d')) 271 | { 272 | log.info('write target:', args[0]) 273 | // args[0] = new NativePointer(0x1) 274 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 275 | log.info(args[2].toInt32()) 276 | log.info(args[3].readUtf8String()) 277 | log.info(args[5].readByteArray(16)) 278 | 279 | const printf = new VSprintf(format, args[5]) 280 | log.info(printf.toString()) 281 | } 282 | } 283 | catch (error) { 284 | log.info('error:', error) 285 | } 286 | 287 | /* 288 | dumpAddr('Input', args[0], args[3].toInt32()); 289 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 290 | this.outsize = args[2].toInt32(); 291 | */ 292 | }, 293 | 294 | // When function is finished 295 | onLeave: function (retval) { 296 | /* 297 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 298 | log.info('[+] Returned from SomeFunc: ' + retval); 299 | */ 300 | log.info('retval:', retval) 301 | log.info(`onLeave\n\n`); 302 | } 303 | }); 304 | } 305 | } 306 | { 307 | const targetAddr = baseAddr.resolveAddress('0x035BC444') 308 | if (targetAddr != null) { 309 | const log = useLogger('vswprintf_s') 310 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 311 | 312 | // When function is called, print out its parameters 313 | /* 314 | 以下内容演示了 315 | 1. 怎么提取 printf 的第一个参数的字符串 316 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 317 | 其他API 用法 318 | https://frida.re/docs/javascript-api/ 319 | */ 320 | onEnter: function (args) { 321 | try { 322 | log.info(`onEnter`); 323 | log.info('[+] Called targetAddr:' + targetAddr); 324 | const format = args[3].readUtf8String() 325 | if (format && !format.startsWith('%d-%02d-%02d')) 326 | { 327 | log.info('write target:', args[0]) 328 | // args[0] = new NativePointer(0x1) 329 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 330 | log.info(args[2].toInt32()) 331 | log.info(args[3].readUtf8String()) 332 | log.info(args[5].readByteArray(16)) 333 | 334 | const printf = new VSprintf(format, args[5]) 335 | log.info(printf.toString()) 336 | } 337 | } 338 | catch (error) { 339 | log.info('error:', error) 340 | } 341 | 342 | /* 343 | dumpAddr('Input', args[0], args[3].toInt32()); 344 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 345 | this.outsize = args[2].toInt32(); 346 | */ 347 | }, 348 | 349 | // When function is finished 350 | onLeave: function (retval) { 351 | /* 352 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 353 | log.info('[+] Returned from SomeFunc: ' + retval); 354 | */ 355 | log.info('retval:', retval) 356 | log.info(`onLeave\n\n`); 357 | } 358 | }); 359 | } 360 | } 361 | { 362 | const targetAddr = baseAddr.resolveAddress('0x035BC558') 363 | if (targetAddr != null) { 364 | const log = useLogger('vsnwprintf_s') 365 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 366 | 367 | // When function is called, print out its parameters 368 | /* 369 | 以下内容演示了 370 | 1. 怎么提取 printf 的第一个参数的字符串 371 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 372 | 其他API 用法 373 | https://frida.re/docs/javascript-api/ 374 | */ 375 | onEnter: function (args) { 376 | try { 377 | log.info(`onEnter`); 378 | log.info('[+] Called targetAddr:' + targetAddr); 379 | const format = args[3].readUtf8String() 380 | if (format && !format.startsWith('%d-%02d-%02d')) 381 | { 382 | log.info('write target:', args[0]) 383 | // args[0] = new NativePointer(0x1) 384 | log.info(args[1].readPointer().readByteArray(args[2].toInt32())) 385 | log.info(args[2].toInt32()) 386 | log.info(args[3].readUtf8String()) 387 | log.info(args[5].readByteArray(16)) 388 | 389 | const printf = new VSprintf(format, args[5]) 390 | log.info(printf.toString()) 391 | } 392 | } 393 | catch (error) { 394 | log.info('error:', error) 395 | } 396 | 397 | /* 398 | dumpAddr('Input', args[0], args[3].toInt32()); 399 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 400 | this.outsize = args[2].toInt32(); 401 | */ 402 | }, 403 | 404 | // When function is finished 405 | onLeave: function (retval) { 406 | /* 407 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 408 | log.info('[+] Returned from SomeFunc: ' + retval); 409 | */ 410 | log.info('retval:', retval) 411 | log.info(`onLeave\n\n`); 412 | } 413 | }); 414 | } 415 | } 416 | // { 417 | // const targetAddr = baseAddr.resolveAddress('0x002888DC') 418 | // if (targetAddr != null) { 419 | // const log = useLogger('output overwrite') 420 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 421 | 422 | // // When function is called, print out its parameters 423 | // /* 424 | // 以下内容演示了 425 | // 1. 怎么提取 printf 的第一个参数的字符串 426 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 427 | // 其他API 用法 428 | // https://frida.re/docs/javascript-api/ 429 | // */ 430 | // onEnter: function (args) { 431 | // try { 432 | // log.info(`onEnter`); 433 | // log.info('[+] Called targetAddr:' + targetAddr); 434 | // } 435 | // catch (error) { 436 | // log.info('error:', error) 437 | // } 438 | 439 | // /* 440 | // dumpAddr('Input', args[0], args[3].toInt32()); 441 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 442 | // this.outsize = args[2].toInt32(); 443 | // */ 444 | // }, 445 | 446 | // // When function is finished 447 | // onLeave: function (retval) { 448 | // /* 449 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 450 | // log.info('[+] Returned from SomeFunc: ' + retval); 451 | // */ 452 | // log.info('retval:', retval) 453 | // log.info(`onLeave\n\n`); 454 | // retval.replace(new NativePointer(0x1)) 455 | // } 456 | // }); 457 | // } 458 | // } 459 | // { 460 | // const target = 'forwardMsg' 461 | // const targetAddr = baseAddr.resolveAddress('0x11FE480') 462 | // if (targetAddr != null) { 463 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 464 | 465 | // // When function is called, print out its parameters 466 | // /* 467 | // 以下内容演示了 468 | // 1. 怎么提取 printf 的第一个参数的字符串 469 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 470 | // 其他API 用法 471 | // https://frida.re/docs/javascript-api/ 472 | // */ 473 | // onEnter: function (args) { 474 | // try { 475 | // console.log(`${target} - onEnter`); 476 | // console.log('[+] Called targetAddr:' + targetAddr); 477 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 478 | // // console.log('arg0:', readStdString(args[0])) 479 | // console.log('[+] Argv0: ', args[0]) 480 | // const p = args[0].readPointer() 481 | // const pLength = p.add(4 * 4).readInt() 482 | // console.log('pLength:', pLength) 483 | 484 | // const pList = p.add(8).readPointer() 485 | // const msgList = pList.readPointer() 486 | // const msgLength = msgList.add('0xB').readInt() / 2 487 | // console.log('msgLength:', msgLength) 488 | // const _list = msgList.add(0x5a) 489 | // for (let i = 0; i < msgLength; i++) { 490 | // const msg = _list.add(0xa4 * i) 491 | // const len = msg.add(0x35) 492 | // console.log('len:', len.readInt()) 493 | // const msgId = len.add(4).readCString(len.readInt()) 494 | // console.log(`msg[${i}]:`, msgId) 495 | // } 496 | 497 | // const fromPeer = pList.add(1 * 8).readPointer() 498 | // const fromId = fromPeer.add(48) 499 | // const _fromId = fromId.add(0xb).readCString(fromId.add(7).readInt()) 500 | // console.log('chatType:', fromPeer.add(0xb).readInt() / 2, 'id:', _fromId) 501 | // const toPeer = pList.add(2 * 8).readPointer() 502 | // const toId = toPeer.add(48) 503 | // const _toId = toId.add(0xb).readCString(toId.add(7).readInt()) 504 | // console.log('chatType:', toPeer.add(0xb).readInt() / 2, 'id:', _toId) 505 | 506 | // const cmtList = pList.add(3 * 8).readPointer() 507 | // const attrMap = pList.add(4 * 8).readPointer() 508 | // } 509 | // catch (error) { 510 | // console.log('error:', error) 511 | // } 512 | 513 | // /* 514 | // dumpAddr('Input', args[0], args[3].toInt32()); 515 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 516 | // this.outsize = args[2].toInt32(); 517 | // */ 518 | // }, 519 | 520 | // // When function is finished 521 | // onLeave: function (retval) { 522 | // /* 523 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 524 | // console.log('[+] Returned from SomeFunc: ' + retval); 525 | // */ 526 | // // console.log('retval:', new StdString(retval).toString()) 527 | // console.log(`${target} - onLeave\n\n`); 528 | // } 529 | // }); 530 | // } 531 | // } 532 | const logAdd = (addr: string) => { 533 | const target = 'log - ' + addr 534 | const targetAddr = baseAddr.resolveAddress(addr) 535 | if (targetAddr != null) { 536 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 537 | 538 | // When function is called, print out its parameters 539 | /* 540 | 以下内容演示了 541 | 1. 怎么提取 printf 的第一个参数的字符串 542 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 543 | 其他API 用法 544 | https://frida.re/docs/javascript-api/ 545 | */ 546 | onEnter: function (args) { 547 | try { 548 | 549 | console.log(`\n${target} - onEnter`); 550 | console.log('[+] Called targetAddr:' + targetAddr); 551 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 552 | // console.log('arg0:', readStdString(args[0])) 553 | console.log('[+] Argv0: ', args[0]) 554 | 555 | for (let i = 0; i < 12; i++) { 556 | const cur = args[i] 557 | console.log(`a${i + 1} :`, cur) 558 | try { 559 | console.log(`a${i + 1} int:`, cur.readInt()) 560 | console.log(`a${i + 1} raw str:`, cur.readUtf8String()) 561 | 562 | }catch{ 563 | // console.log('read str error') 564 | } 565 | try { 566 | const ptr = cur.readPointer() 567 | console.log(`a${i + 1} ptr:`, ptr) 568 | console.log(`a${i + 1} str:`, ptr.readUtf8String()) 569 | } catch (error) { 570 | // console.log('read std::str error') 571 | } 572 | 573 | } 574 | } 575 | catch (error) { 576 | console.log('error:', error) 577 | } 578 | 579 | /* 580 | dumpAddr('Input', args[0], args[3].toInt32()); 581 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 582 | this.outsize = args[2].toInt32(); 583 | */ 584 | }, 585 | 586 | // When function is finished 587 | onLeave: function (retval) { 588 | /* 589 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 590 | console.log('[+] Returned from SomeFunc: ' + retval); 591 | */ 592 | // console.log('retval:', new StdString(retval).toString()) 593 | console.log(`${target} - onLeave\n\n`); 594 | console.log('\n') 595 | } 596 | }); 597 | } 598 | } 599 | const logList = [ 600 | '0x01BD215D', 601 | '0x0804f', // 00007FFAA3DFCF10 602 | '0x00001471', 603 | '0x0004BE56', 604 | ] 605 | for (const addr of logList) { 606 | logAdd(addr) 607 | } 608 | // { 609 | // const target = 'log58BE80' 610 | // const targetAddr = baseAddr.resolveAddress('0x58BE80') 611 | // if (targetAddr != null) { 612 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 613 | 614 | // // When function is called, print out its parameters 615 | // /* 616 | // 以下内容演示了 617 | // 1. 怎么提取 printf 的第一个参数的字符串 618 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 619 | // 其他API 用法 620 | // https://frida.re/docs/javascript-api/ 621 | // */ 622 | // onEnter: function (args) { 623 | // try { 624 | // console.log(`${target} - onEnter`); 625 | // console.log('[+] Called targetAddr:' + targetAddr); 626 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 627 | // // console.log('arg0:', readStdString(args[0])) 628 | // console.log('[+] Argv0: ', args[0]) 629 | // const a1 = args[0].readPointer() 630 | // const a2 = args[1].readPointer() 631 | // console.log('a2:', a2.readUtf8String()) 632 | // try { 633 | // const a3 = args[2].readPointer() 634 | // console.log('a3:', a3.readUtf8String()) 635 | // } 636 | // catch(e) { 637 | // const a3 = args[2].readInt() 638 | // console.log('a3 try to read int:', a3) 639 | // } 640 | // } 641 | // catch (error) { 642 | // console.log('error:', error) 643 | // } 644 | 645 | // /* 646 | // dumpAddr('Input', args[0], args[3].toInt32()); 647 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 648 | // this.outsize = args[2].toInt32(); 649 | // */ 650 | // }, 651 | 652 | // // When function is finished 653 | // onLeave: function (retval) { 654 | // /* 655 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 656 | // console.log('[+] Returned from SomeFunc: ' + retval); 657 | // */ 658 | // // console.log('retval:', new StdString(retval).toString()) 659 | // console.log(`${target} - onLeave\n\n`); 660 | // } 661 | // }); 662 | // } 663 | // } 664 | // { 665 | // const target = 'log58BF40' 666 | // const targetAddr = baseAddr.resolveAddress('0x58BF40') 667 | // if (targetAddr != null) { 668 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 669 | 670 | // // When function is called, print out its parameters 671 | // /* 672 | // 以下内容演示了 673 | // 1. 怎么提取 printf 的第一个参数的字符串 674 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 675 | // 其他API 用法 676 | // https://frida.re/docs/javascript-api/ 677 | // */ 678 | // onEnter: function (args) { 679 | // try { 680 | // console.log(`${target} - onEnter`); 681 | // console.log('[+] Called targetAddr:' + targetAddr); 682 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 683 | // // console.log('arg0:', readStdString(args[0])) 684 | // console.log('[+] Argv0: ', args[0]) 685 | // const a1 = args[0].readPointer() 686 | // const a2 = args[1].readPointer() 687 | // console.log('a2:', a2.readUtf8String()) 688 | // try { 689 | // const a3 = args[2].readPointer() 690 | // console.log('a3:', a3.readUtf8String()) 691 | // } 692 | // catch(e) { 693 | // const a3 = args[2].readInt() 694 | // console.log('a3 try to read int:', a3) 695 | // } 696 | // try { 697 | // const a4 = args[3].readPointer() 698 | // // const len = args[3].add(16).readInt() 699 | // // const byte = a4.readByteArray(len) 700 | // console.log('a4:', a4.readUtf8String()) 701 | // }catch(e) { 702 | // const a4 = args[3].readInt() 703 | // console.log('a4 try to read int:', a4) 704 | // } 705 | // } 706 | // catch (error) { 707 | // console.log('error:', error) 708 | // } 709 | 710 | // /* 711 | // dumpAddr('Input', args[0], args[3].toInt32()); 712 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 713 | // this.outsize = args[2].toInt32(); 714 | // */ 715 | // }, 716 | 717 | // // When function is finished 718 | // onLeave: function (retval) { 719 | // /* 720 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 721 | // console.log('[+] Returned from SomeFunc: ' + retval); 722 | // */ 723 | // // console.log('retval:', new StdString(retval).toString()) 724 | // console.log(`${target} - onLeave\n\n`); 725 | // } 726 | // }); 727 | // } 728 | // } 729 | // { 730 | // const target = 'log58C4E0' 731 | // const targetAddr = baseAddr.resolveAddress('0x58C4E0') 732 | // if (targetAddr != null) { 733 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 734 | 735 | // // When function is called, print out its parameters 736 | // /* 737 | // 以下内容演示了 738 | // 1. 怎么提取 printf 的第一个参数的字符串 739 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 740 | // 其他API 用法 741 | // https://frida.re/docs/javascript-api/ 742 | // */ 743 | // onEnter: function (args) { 744 | // try { 745 | // console.log(`${target} - onEnter`); 746 | // console.log('[+] Called targetAddr:' + targetAddr); 747 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 748 | // // console.log('arg0:', readStdString(args[0])) 749 | // console.log('[+] Argv0: ', args[0]) 750 | // const a1 = args[0].readPointer() 751 | // const a2 = args[1].readPointer() 752 | // console.log('a2:', a2.readUtf8String()) 753 | // try { 754 | // const a3 = args[2].readPointer() 755 | // console.log('a3:', a3.readUtf8String()) 756 | // } 757 | // catch(e) { 758 | // const a3 = args[2].readInt() 759 | // console.log('a3 try to read int:', a3) 760 | // } 761 | // try { 762 | // const a4 = args[3].readPointer() 763 | // // const len = args[3].add(16).readInt() 764 | // // const byte = a4.readByteArray(len) 765 | // console.log('a4:', a4.readUtf8String()) 766 | // }catch(e) { 767 | // const a4 = args[3].readInt() 768 | // console.log('a4 try to read int:', a4) 769 | // } 770 | // } 771 | // catch (error) { 772 | // console.log('error:', error) 773 | // } 774 | 775 | // /* 776 | // dumpAddr('Input', args[0], args[3].toInt32()); 777 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 778 | // this.outsize = args[2].toInt32(); 779 | // */ 780 | // }, 781 | 782 | // // When function is finished 783 | // onLeave: function (retval) { 784 | // /* 785 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 786 | // console.log('[+] Returned from SomeFunc: ' + retval); 787 | // */ 788 | // // console.log('retval:', new StdString(retval).toString()) 789 | // console.log(`${target} - onLeave\n\n`); 790 | // } 791 | // }); 792 | // } 793 | // } 794 | // { 795 | // const target = 'log69B427' 796 | // const targetAddr = baseAddr.resolveAddress('0x69B427') 797 | // if (targetAddr != null) { 798 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 799 | 800 | // // When function is called, print out its parameters 801 | // /* 802 | // 以下内容演示了 803 | // 1. 怎么提取 printf 的第一个参数的字符串 804 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 805 | // 其他API 用法 806 | // https://frida.re/docs/javascript-api/ 807 | // */ 808 | // onEnter: function (args) { 809 | // try { 810 | // console.log(`${target} - onEnter`); 811 | // console.log('[+] Called targetAddr:' + targetAddr); 812 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 813 | // // console.log('arg0:', readStdString(args[0])) 814 | // console.log('[+] Argv0: ', args[0]) 815 | // const a1 = args[0].readPointer() 816 | // const a2 = args[1].readPointer() 817 | // console.log('a2:', a2.readUtf8String()) 818 | // try { 819 | // const a3 = args[2].readPointer() 820 | // console.log('a3:', a3.readUtf8String()) 821 | // } 822 | // catch(e) { 823 | // const a3 = args[2].readInt() 824 | // console.log('a3 try to read int:', a3) 825 | // } 826 | // try { 827 | // const a4 = args[3].readPointer() 828 | // console.log('a4:', a4.readUtf8String()) 829 | // }catch(e) { 830 | // const a4 = args[3].readInt() 831 | // console.log('a4 try to read int:', a4) 832 | // } 833 | // } 834 | // catch (error) { 835 | // console.log('error:', error) 836 | // } 837 | 838 | // /* 839 | // dumpAddr('Input', args[0], args[3].toInt32()); 840 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 841 | // this.outsize = args[2].toInt32(); 842 | // */ 843 | // }, 844 | 845 | // // When function is finished 846 | // onLeave: function (retval) { 847 | // /* 848 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 849 | // console.log('[+] Returned from SomeFunc: ' + retval); 850 | // */ 851 | // // console.log('retval:', new StdString(retval).toString()) 852 | // console.log(`${target} - onLeave\n\n`); 853 | // } 854 | // }); 855 | // } 856 | // } 857 | // { 858 | // const target = 'log031A7850' 859 | // const targetAddr = baseAddr.resolveAddress('0x031A7850') 860 | // if (targetAddr != null) { 861 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 862 | 863 | // // When function is called, print out its parameters 864 | // /* 865 | // 以下内容演示了 866 | // 1. 怎么提取 printf 的第一个参数的字符串 867 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 868 | // 其他API 用法 869 | // https://frida.re/docs/javascript-api/ 870 | // */ 871 | // onEnter: function (args) { 872 | // try { 873 | // console.log(`${target} - onEnter`); 874 | // console.log('[+] Called targetAddr:' + targetAddr); 875 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 876 | // // console.log('arg0:', readStdString(args[0])) 877 | // console.log('[+] Argv0: ', args[0]) 878 | // const a1 = args[0].readPointer() 879 | // const a2 = args[1].readPointer() 880 | // console.log('a2:', a2.readUtf8String()) 881 | // try { 882 | // const a3 = args[2].readPointer() 883 | // console.log('a3:', a3.readUtf8String()) 884 | // } 885 | // catch(e) { 886 | // const a3 = args[2].readInt() 887 | // console.log('a3 try to read int:', a3) 888 | // } 889 | // try { 890 | // const a4 = args[3].readPointer() 891 | // console.log('a4:', a4.readUtf8String()) 892 | // }catch(e) { 893 | // const a4 = args[3].readInt() 894 | // console.log('a4 try to read int:', a4) 895 | // } 896 | // try { 897 | // const a5 = args[4].readPointer() 898 | // console.log('a5:', a5.readUtf8String()) 899 | // }catch(e) { 900 | // const a5 = args[4].readInt() 901 | // console.log('a45try to read int:', a5) 902 | // } 903 | // try { 904 | // const a6 = args[5].readPointer() 905 | // console.log('a6:', a6.readUtf8String()) 906 | // }catch(e) { 907 | // const a6 = args[5].readInt() 908 | // console.log('a6 try to read int:', a6) 909 | // } 910 | // try { 911 | // const a7 = args[6].readPointer() 912 | // console.log('a7:', a7.readUtf8String()) 913 | // }catch(e) { 914 | // const a7 = args[6].readInt() 915 | // console.log('a7 try to read int:', a7) 916 | // } 917 | // } 918 | // catch (error) { 919 | // console.log('error:', error) 920 | // } 921 | 922 | // /* 923 | // dumpAddr('Input', args[0], args[3].toInt32()); 924 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 925 | // this.outsize = args[2].toInt32(); 926 | // */ 927 | // }, 928 | 929 | // // When function is finished 930 | // onLeave: function (retval) { 931 | // /* 932 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 933 | // console.log('[+] Returned from SomeFunc: ' + retval); 934 | // */ 935 | // // console.log('retval:', new StdString(retval).toString()) 936 | // console.log(`${target} - onLeave\n\n`); 937 | // } 938 | // }); 939 | // } 940 | // } 941 | // { 942 | // const addr = "02F7B780" 943 | // const target = 'SQL' + addr 944 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 945 | // if (targetAddr != null) { 946 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 947 | 948 | // // When function is called, print out its parameters 949 | // /* 950 | // 以下内容演示了 951 | // 1. 怎么提取 printf 的第一个参数的字符串 952 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 953 | // 其他API 用法 954 | // https://frida.re/docs/javascript-api/ 955 | // */ 956 | // onEnter: function (args) { 957 | // try { 958 | // console.log(`${target} - onEnter`); 959 | // console.log('[+] Called targetAddr:' + targetAddr); 960 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 961 | // // console.log('arg0:', readStdString(args[0])) 962 | // console.log('[+] Argv0: ', args[0]) 963 | // try { 964 | 965 | // const a1 = args[0].readPointer() 966 | // } catch (error) { 967 | // const a1 = args[0].readInt() 968 | // console.log('a1 try to read int:', a1) 969 | // } 970 | // try { 971 | 972 | // const a2 = args[1].readPointer() 973 | // console.log('a2:', a2.readUtf8String()) 974 | // } catch (error) { 975 | // const a2 = args[1].readInt() 976 | // console.log('a2 try to read int:', a2) 977 | // } 978 | // try { 979 | // const a3 = args[2].readPointer() 980 | // console.log('a3:', a3.readUtf8String()) 981 | // } 982 | // catch(e) { 983 | // const a3 = args[2].readInt() 984 | // console.log('a3 try to read int:', a3) 985 | // } 986 | // try { 987 | // const a4 = args[3].readPointer() 988 | // console.log('a4:', a4.readUtf8String()) 989 | // }catch(e) { 990 | // const a4 = args[3].readInt() 991 | // console.log('a4 try to read int:', a4) 992 | // } 993 | // try { 994 | // const a5 = args[4].readPointer() 995 | // console.log('a5:', a5.readUtf8String()) 996 | // }catch(e) { 997 | // const a5 = args[4].readInt() 998 | // console.log('a45try to read int:', a5) 999 | // } 1000 | // try { 1001 | // const a6 = args[5].readPointer() 1002 | // console.log('a6:', a6.readUtf8String()) 1003 | // }catch(e) { 1004 | // const a6 = args[5].readInt() 1005 | // console.log('a6 try to read int:', a6) 1006 | // } 1007 | // try { 1008 | // const a7 = args[6].readPointer() 1009 | // console.log('a7:', a7.readUtf8String()) 1010 | // }catch(e) { 1011 | // const a7 = args[6].readInt() 1012 | // console.log('a7 try to read int:', a7) 1013 | // } 1014 | // } 1015 | // catch (error) { 1016 | // console.log('error:', error) 1017 | // } 1018 | 1019 | // /* 1020 | // dumpAddr('Input', args[0], args[3].toInt32()); 1021 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1022 | // this.outsize = args[2].toInt32(); 1023 | // */ 1024 | // }, 1025 | 1026 | // // When function is finished 1027 | // onLeave: function (retval) { 1028 | // /* 1029 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1030 | // console.log('[+] Returned from SomeFunc: ' + retval); 1031 | // */ 1032 | // // console.log('retval:', new StdString(retval).toString()) 1033 | // console.log(`${target} - onLeave\n\n`); 1034 | // } 1035 | // }); 1036 | // } 1037 | // } 1038 | // { 1039 | // const target = 'SQL03266770' 1040 | // const targetAddr = baseAddr.resolveAddress('0x03266770') 1041 | // if (targetAddr != null) { 1042 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1043 | 1044 | // // When function is called, print out its parameters 1045 | // /* 1046 | // 以下内容演示了 1047 | // 1. 怎么提取 printf 的第一个参数的字符串 1048 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1049 | // 其他API 用法 1050 | // https://frida.re/docs/javascript-api/ 1051 | // */ 1052 | // onEnter: function (args) { 1053 | // try { 1054 | // console.log(`${target} - onEnter`); 1055 | // console.log('[+] Called targetAddr:' + targetAddr); 1056 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1057 | // // console.log('arg0:', readStdString(args[0])) 1058 | // console.log('[+] Argv0: ', args[0]) 1059 | // try { 1060 | 1061 | // const a1 = args[0].readUtf8String() 1062 | // console.log('a1:', a1) 1063 | // } catch (error) { 1064 | // const a1 = args[0].readInt() 1065 | // console.log('a1 try to read int:', a1) 1066 | // } 1067 | // try { 1068 | 1069 | // console.log('a2:', args[1]) 1070 | // // const a2 = args[1].readPointer() 1071 | // // console.log('a2 str:', a2.readUtf8String()) 1072 | // } catch (error) { 1073 | // const a2 = args[1].readInt() 1074 | // console.log('a2 try to read int:', a2) 1075 | // } 1076 | // try { 1077 | // const a3 = args[2] 1078 | // console.log('a3:', a3) 1079 | // } 1080 | // catch(e) { 1081 | // const a3 = args[2].readInt() 1082 | // console.log('a3 try to read int:', a3) 1083 | // } 1084 | // try { 1085 | // const a4 = args[3] 1086 | // console.log('a4:', a4) 1087 | // }catch(e) { 1088 | // const a4 = args[3].readInt() 1089 | // console.log('a4 try to read int:', a4) 1090 | // } 1091 | // try { 1092 | // const a5 = args[4] 1093 | // console.log('a5:', a5) 1094 | // }catch(e) { 1095 | // const a5 = args[4].readInt() 1096 | // console.log('a45try to read int:', a5) 1097 | // } 1098 | // try { 1099 | // const a6 = args[5] 1100 | // console.log('a6:', a6) 1101 | // }catch(e) { 1102 | // const a6 = args[5].readInt() 1103 | // console.log('a6 try to read int:', a6) 1104 | // } 1105 | // try { 1106 | // const a7 = args[6].readPointer() 1107 | // console.log('a7:', a7.readUtf8String()) 1108 | // }catch(e) { 1109 | // const a7 = args[6].readInt() 1110 | // console.log('a7 try to read int:', a7) 1111 | // } 1112 | // } 1113 | // catch (error) { 1114 | // console.log('error:', error) 1115 | // } 1116 | 1117 | // /* 1118 | // dumpAddr('Input', args[0], args[3].toInt32()); 1119 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1120 | // this.outsize = args[2].toInt32(); 1121 | // */ 1122 | // }, 1123 | 1124 | // // When function is finished 1125 | // onLeave: function (retval) { 1126 | // /* 1127 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1128 | // console.log('[+] Returned from SomeFunc: ' + retval); 1129 | // */ 1130 | // // console.log('retval:', new StdString(retval).toString()) 1131 | // console.log(`${target} - onLeave\n\n`); 1132 | // } 1133 | // }); 1134 | // } 1135 | // } 1136 | // { 1137 | // const addr = "03275930" 1138 | // const target = 'SQL' + addr 1139 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 1140 | // if (targetAddr != null) { 1141 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1142 | 1143 | // // When function is called, print out its parameters 1144 | // /* 1145 | // 以下内容演示了 1146 | // 1. 怎么提取 printf 的第一个参数的字符串 1147 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1148 | // 其他API 用法 1149 | // https://frida.re/docs/javascript-api/ 1150 | // */ 1151 | // onEnter: function (args) { 1152 | // try { 1153 | // console.log(`${target} - onEnter`); 1154 | // console.log('[+] Called targetAddr:' + targetAddr); 1155 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1156 | // // console.log('arg0:', readStdString(args[0])) 1157 | // console.log('[+] Argv0: ', args[0]) 1158 | // try { 1159 | 1160 | // const a1 = args[0].readPointer() 1161 | // } catch (error) { 1162 | // const a1 = args[0].readInt() 1163 | // console.log('a1 try to read int:', a1) 1164 | // } 1165 | // try { 1166 | 1167 | // const a2 = args[1].readPointer() 1168 | // console.log('a2:', a2.readUtf8String()) 1169 | // } catch (error) { 1170 | // const a2 = args[1].readInt() 1171 | // console.log('a2 try to read int:', a2) 1172 | // } 1173 | // try { 1174 | // const a3 = args[2].readPointer() 1175 | // console.log('a3:', a3.readUtf8String()) 1176 | // } 1177 | // catch(e) { 1178 | // const a3 = args[2].readInt() 1179 | // console.log('a3 try to read int:', a3) 1180 | // } 1181 | // try { 1182 | // const a4 = args[3].readPointer() 1183 | // console.log('a4:', a4.readUtf8String()) 1184 | // }catch(e) { 1185 | // const a4 = args[3].readInt() 1186 | // console.log('a4 try to read int:', a4) 1187 | // } 1188 | // try { 1189 | // const a5 = args[4].readPointer() 1190 | // console.log('a5:', a5.readUtf8String()) 1191 | // }catch(e) { 1192 | // const a5 = args[4].readInt() 1193 | // console.log('a45try to read int:', a5) 1194 | // } 1195 | // try { 1196 | // const a6 = args[5].readPointer() 1197 | // console.log('a6:', a6.readUtf8String()) 1198 | // }catch(e) { 1199 | // const a6 = args[5].readInt() 1200 | // console.log('a6 try to read int:', a6) 1201 | // } 1202 | // try { 1203 | // const a7 = args[6].readPointer() 1204 | // console.log('a7:', a7.readUtf8String()) 1205 | // }catch(e) { 1206 | // const a7 = args[6].readInt() 1207 | // console.log('a7 try to read int:', a7) 1208 | // } 1209 | // } 1210 | // catch (error) { 1211 | // console.log('error:', error) 1212 | // } 1213 | 1214 | // /* 1215 | // dumpAddr('Input', args[0], args[3].toInt32()); 1216 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1217 | // this.outsize = args[2].toInt32(); 1218 | // */ 1219 | // }, 1220 | 1221 | // // When function is finished 1222 | // onLeave: function (retval) { 1223 | // /* 1224 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1225 | // console.log('[+] Returned from SomeFunc: ' + retval); 1226 | // */ 1227 | // // console.log('retval:', new StdString(retval).toString()) 1228 | // console.log(`${target} - onLeave\n\n`); 1229 | // } 1230 | // }); 1231 | // } 1232 | // } 1233 | // { 1234 | // const addr = "032AD9F0" 1235 | // const target = 'SQL' + addr 1236 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 1237 | // if (targetAddr != null) { 1238 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1239 | 1240 | // // When function is called, print out its parameters 1241 | // /* 1242 | // 以下内容演示了 1243 | // 1. 怎么提取 printf 的第一个参数的字符串 1244 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1245 | // 其他API 用法 1246 | // https://frida.re/docs/javascript-api/ 1247 | // */ 1248 | // onEnter: function (args) { 1249 | // try { 1250 | // console.log(`${target} - onEnter`); 1251 | // console.log('[+] Called targetAddr:' + targetAddr); 1252 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1253 | // // console.log('arg0:', readStdString(args[0])) 1254 | // console.log('[+] Argv0: ', args[0]) 1255 | // try { 1256 | 1257 | // const a1 = args[0].readPointer() 1258 | // } catch (error) { 1259 | // const a1 = args[0].readInt() 1260 | // console.log('a1 try to read int:', a1) 1261 | // } 1262 | // try { 1263 | 1264 | // const a2 = args[1].readPointer() 1265 | // console.log('a2:', a2.readUtf8String()) 1266 | // } catch (error) { 1267 | // const a2 = args[1].readInt() 1268 | // console.log('a2 try to read int:', a2) 1269 | // } 1270 | // try { 1271 | // const a3 = args[2].readPointer() 1272 | // console.log('a3:', a3.readUtf8String()) 1273 | // } 1274 | // catch(e) { 1275 | // const a3 = args[2].readInt() 1276 | // console.log('a3 try to read int:', a3) 1277 | // } 1278 | // try { 1279 | // const a4 = args[3].readPointer() 1280 | // console.log('a4:', a4.readUtf8String()) 1281 | // }catch(e) { 1282 | // const a4 = args[3].readInt() 1283 | // console.log('a4 try to read int:', a4) 1284 | // } 1285 | // try { 1286 | // const a5 = args[4].readPointer() 1287 | // console.log('a5:', a5.readUtf8String()) 1288 | // }catch(e) { 1289 | // const a5 = args[4].readInt() 1290 | // console.log('a45try to read int:', a5) 1291 | // } 1292 | // try { 1293 | // const a6 = args[5].readPointer() 1294 | // console.log('a6:', a6.readUtf8String()) 1295 | // }catch(e) { 1296 | // const a6 = args[5].readInt() 1297 | // console.log('a6 try to read int:', a6) 1298 | // } 1299 | // try { 1300 | // const a7 = args[6].readPointer() 1301 | // console.log('a7:', a7.readUtf8String()) 1302 | // }catch(e) { 1303 | // const a7 = args[6].readInt() 1304 | // console.log('a7 try to read int:', a7) 1305 | // } 1306 | // } 1307 | // catch (error) { 1308 | // console.log('error:', error) 1309 | // } 1310 | 1311 | // /* 1312 | // dumpAddr('Input', args[0], args[3].toInt32()); 1313 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1314 | // this.outsize = args[2].toInt32(); 1315 | // */ 1316 | // }, 1317 | 1318 | // // When function is finished 1319 | // onLeave: function (retval) { 1320 | // /* 1321 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1322 | // console.log('[+] Returned from SomeFunc: ' + retval); 1323 | // */ 1324 | // // console.log('retval:', new StdString(retval).toString()) 1325 | // console.log(`${target} - onLeave\n\n`); 1326 | // } 1327 | // }); 1328 | // } 1329 | // } 1330 | // { 1331 | // const addr = "032DAE50" 1332 | // const target = 'SQL' + addr 1333 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 1334 | // if (targetAddr != null) { 1335 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1336 | 1337 | // // When function is called, print out its parameters 1338 | // /* 1339 | // 以下内容演示了 1340 | // 1. 怎么提取 printf 的第一个参数的字符串 1341 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1342 | // 其他API 用法 1343 | // https://frida.re/docs/javascript-api/ 1344 | // */ 1345 | // onEnter: function (args) { 1346 | // try { 1347 | // console.log(`${target} - onEnter`); 1348 | // console.log('[+] Called targetAddr:' + targetAddr); 1349 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1350 | // // console.log('arg0:', readStdString(args[0])) 1351 | // console.log('[+] Argv0: ', args[0]) 1352 | // try { 1353 | 1354 | // const a1 = args[0].readPointer() 1355 | // } catch (error) { 1356 | // const a1 = args[0].readInt() 1357 | // console.log('a1 try to read int:', a1) 1358 | // } 1359 | // try { 1360 | 1361 | // const a2 = args[1].readPointer() 1362 | // console.log('a2:', a2.readUtf8String()) 1363 | // } catch (error) { 1364 | // const a2 = args[1].readInt() 1365 | // console.log('a2 try to read int:', a2) 1366 | // } 1367 | // try { 1368 | // const a3 = args[2].readPointer() 1369 | // console.log('a3:', a3.readUtf8String()) 1370 | // } 1371 | // catch(e) { 1372 | // const a3 = args[2].readInt() 1373 | // console.log('a3 try to read int:', a3) 1374 | // } 1375 | // try { 1376 | // const a4 = args[3].readPointer() 1377 | // console.log('a4:', a4.readUtf8String()) 1378 | // }catch(e) { 1379 | // const a4 = args[3].readInt() 1380 | // console.log('a4 try to read int:', a4) 1381 | // } 1382 | // try { 1383 | // const a5 = args[4].readPointer() 1384 | // console.log('a5:', a5.readUtf8String()) 1385 | // }catch(e) { 1386 | // const a5 = args[4].readInt() 1387 | // console.log('a45try to read int:', a5) 1388 | // } 1389 | // try { 1390 | // const a6 = args[5].readPointer() 1391 | // console.log('a6:', a6.readUtf8String()) 1392 | // }catch(e) { 1393 | // const a6 = args[5].readInt() 1394 | // console.log('a6 try to read int:', a6) 1395 | // } 1396 | // try { 1397 | // const a7 = args[6].readPointer() 1398 | // console.log('a7:', a7.readUtf8String()) 1399 | // }catch(e) { 1400 | // const a7 = args[6].readInt() 1401 | // console.log('a7 try to read int:', a7) 1402 | // } 1403 | // } 1404 | // catch (error) { 1405 | // console.log('error:', error) 1406 | // } 1407 | 1408 | // /* 1409 | // dumpAddr('Input', args[0], args[3].toInt32()); 1410 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1411 | // this.outsize = args[2].toInt32(); 1412 | // */ 1413 | // }, 1414 | 1415 | // // When function is finished 1416 | // onLeave: function (retval) { 1417 | // /* 1418 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1419 | // console.log('[+] Returned from SomeFunc: ' + retval); 1420 | // */ 1421 | // // console.log('retval:', new StdString(retval).toString()) 1422 | // console.log(`${target} - onLeave\n\n`); 1423 | // } 1424 | // }); 1425 | // } 1426 | // } 1427 | // { 1428 | // const addr = "00727180" 1429 | // const target = 'LOG' + addr 1430 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 1431 | // if (targetAddr != null) { 1432 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1433 | 1434 | // // When function is called, print out its parameters 1435 | // /* 1436 | // 以下内容演示了 1437 | // 1. 怎么提取 printf 的第一个参数的字符串 1438 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1439 | // 其他API 用法 1440 | // https://frida.re/docs/javascript-api/ 1441 | // */ 1442 | // onEnter: function (args) { 1443 | // try { 1444 | // console.log(`${target} - onEnter`); 1445 | // console.log('[+] Called targetAddr:' + targetAddr); 1446 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1447 | // // console.log('arg0:', readStdString(args[0])) 1448 | // console.log('[+] Argv0: ', args[0]) 1449 | // try { 1450 | 1451 | // const a1 = args[0].readPointer() 1452 | // } catch (error) { 1453 | // const a1 = args[0].readInt() 1454 | // console.log('a1 try to read int:', a1) 1455 | // } 1456 | // try { 1457 | 1458 | // const a2 = args[1].readPointer() 1459 | // console.log('a2:', a2.readUtf8String()) 1460 | // } catch (error) { 1461 | // const a2 = args[1].readInt() 1462 | // console.log('a2 try to read int:', a2) 1463 | // } 1464 | // try { 1465 | // const a3 = args[2].readPointer() 1466 | // console.log('a3:', a3.readUtf8String()) 1467 | // } 1468 | // catch(e) { 1469 | // const a3 = args[2].readInt() 1470 | // console.log('a3 try to read int:', a3) 1471 | // } 1472 | // try { 1473 | // const a4 = args[3].readPointer() 1474 | // console.log('a4:', a4.readUtf8String()) 1475 | // }catch(e) { 1476 | // const a4 = args[3].readInt() 1477 | // console.log('a4 try to read int:', a4) 1478 | // } 1479 | // try { 1480 | // const a5 = args[4].readPointer() 1481 | // console.log('a5:', a5.readUtf8String()) 1482 | // }catch(e) { 1483 | // const a5 = args[4].readInt() 1484 | // console.log('a45try to read int:', a5) 1485 | // } 1486 | // try { 1487 | // const a6 = args[5].readPointer() 1488 | // console.log('a6:', a6.readUtf8String()) 1489 | // }catch(e) { 1490 | // const a6 = args[5].readInt() 1491 | // console.log('a6 try to read int:', a6) 1492 | // } 1493 | // try { 1494 | // const a7 = args[6].readPointer() 1495 | // console.log('a7:', a7.readUtf8String()) 1496 | // }catch(e) { 1497 | // const a7 = args[6].readInt() 1498 | // console.log('a7 try to read int:', a7) 1499 | // } 1500 | // } 1501 | // catch (error) { 1502 | // console.log('error:', error) 1503 | // } 1504 | 1505 | // /* 1506 | // dumpAddr('Input', args[0], args[3].toInt32()); 1507 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1508 | // this.outsize = args[2].toInt32(); 1509 | // */ 1510 | // }, 1511 | 1512 | // // When function is finished 1513 | // onLeave: function (retval) { 1514 | // /* 1515 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1516 | // console.log('[+] Returned from SomeFunc: ' + retval); 1517 | // */ 1518 | // // console.log('retval:', new StdString(retval).toString()) 1519 | // console.log(`${target} - onLeave\n\n`); 1520 | // } 1521 | // }); 1522 | // } 1523 | // } 1524 | // { 1525 | // const addr = "0074A050" 1526 | // const target = 'LOG' + addr 1527 | // const targetAddr = baseAddr.resolveAddress('0x' + addr) 1528 | // if (targetAddr != null) { 1529 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 1530 | 1531 | // // When function is called, print out its parameters 1532 | // /* 1533 | // 以下内容演示了 1534 | // 1. 怎么提取 printf 的第一个参数的字符串 1535 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 1536 | // 其他API 用法 1537 | // https://frida.re/docs/javascript-api/ 1538 | // */ 1539 | // onEnter: function (args) { 1540 | // try { 1541 | // console.log(`${target} - onEnter`); 1542 | // console.log('[+] Called targetAddr:' + targetAddr); 1543 | // // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 1544 | // // console.log('arg0:', readStdString(args[0])) 1545 | // console.log('[+] Argv0: ', args[0]) 1546 | // try { 1547 | 1548 | // const a1 = args[0].readPointer() 1549 | // } catch (error) { 1550 | // const a1 = args[0].readInt() 1551 | // console.log('a1 try to read int:', a1) 1552 | // } 1553 | // try { 1554 | 1555 | // const a2 = args[1].readPointer() 1556 | // console.log('a2:', a2.readUtf8String()) 1557 | // } catch (error) { 1558 | // const a2 = args[1].readInt() 1559 | // console.log('a2 try to read int:', a2) 1560 | // } 1561 | // try { 1562 | // const a3 = args[2].readPointer() 1563 | // console.log('a3:', a3.readUtf8String()) 1564 | // } 1565 | // catch(e) { 1566 | // const a3 = args[2].readInt() 1567 | // console.log('a3 try to read int:', a3) 1568 | // } 1569 | // try { 1570 | // const a4 = args[3].readPointer() 1571 | // console.log('a4:', a4.readUtf8String()) 1572 | // }catch(e) { 1573 | // const a4 = args[3].readInt() 1574 | // console.log('a4 try to read int:', a4) 1575 | // } 1576 | // try { 1577 | // const a5 = args[4].readPointer() 1578 | // console.log('a5:', a5.readUtf8String()) 1579 | // }catch(e) { 1580 | // const a5 = args[4].readInt() 1581 | // console.log('a45try to read int:', a5) 1582 | // } 1583 | // try { 1584 | // const a6 = args[5].readPointer() 1585 | // console.log('a6:', a6.readUtf8String()) 1586 | // }catch(e) { 1587 | // const a6 = args[5].readInt() 1588 | // console.log('a6 try to read int:', a6) 1589 | // } 1590 | // try { 1591 | // const a7 = args[6].readPointer() 1592 | // console.log('a7:', a7.readUtf8String()) 1593 | // }catch(e) { 1594 | // const a7 = args[6].readInt() 1595 | // console.log('a7 try to read int:', a7) 1596 | // } 1597 | // } 1598 | // catch (error) { 1599 | // console.log('error:', error) 1600 | // } 1601 | 1602 | // /* 1603 | // dumpAddr('Input', args[0], args[3].toInt32()); 1604 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 1605 | // this.outsize = args[2].toInt32(); 1606 | // */ 1607 | // }, 1608 | 1609 | // // When function is finished 1610 | // onLeave: function (retval) { 1611 | // /* 1612 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 1613 | // console.log('[+] Returned from SomeFunc: ' + retval); 1614 | // */ 1615 | // // console.log('retval:', new StdString(retval).toString()) 1616 | // console.log(`${target} - onLeave\n\n`); 1617 | // } 1618 | // }); 1619 | // } 1620 | // } 1621 | } -------------------------------------------------------------------------------- /agent/hook/nt/msf.ts: -------------------------------------------------------------------------------- 1 | import BaseAddr from "../utils/addr.js"; 2 | import { useLogger } from "../../utils/log.js"; 3 | 4 | /** 5 | * 大小:208 6 | */ 7 | class MsfParse { 8 | /** 9 | * *v42 10 | */ 11 | private p: NativePointer 12 | constructor(p: NativePointer) { 13 | this.p = p 14 | } 15 | get uin() { 16 | return this.p.add(4 * Process.pointerSize).readUtf8String() 17 | } 18 | get seq() { 19 | return this.p.add(8 * Process.pointerSize).readInt() 20 | } 21 | get cmd() { 22 | console.log(this.p.readPointer().readByteArray(32)) 23 | return this.p.readPointer().readUtf8String() 24 | } 25 | get dataSize() { 26 | const v4 = this.p.readPointer() 27 | const start = v4.add(32).readPointer() 28 | const end = start.add(8) 29 | return end.readPointer().sub(start.readPointer()).toInt32() 30 | } 31 | get data() { 32 | const v4 = this.p.readPointer() 33 | const startPtr = v4.add(32).readPointer().readPointer() 34 | return startPtr.readByteArray(this.dataSize) 35 | } 36 | } 37 | 38 | export const hookMSF = (baseAddr: BaseAddr) => { 39 | // { 40 | // // 验证pkg创建后,是否执行内存清空操作 41 | // 验证结果:OK 42 | // const targetAddr = baseAddr.resolveAddress('0x035FF2F0') 43 | // if (targetAddr != null) { 44 | // const log = useLogger('MSF pkg clear verify') 45 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 46 | 47 | // // When function is called, print out its parameters 48 | // /* 49 | // 以下内容演示了 50 | // 1. 怎么提取 printf 的第一个参数的字符串 51 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 52 | // 其他API 用法 53 | // https://frida.re/docs/javascript-api/ 54 | // */ 55 | // onEnter: function (args) { 56 | // try { 57 | // log.info(`onEnter`); 58 | // log.info('[+] Called targetAddr:' + targetAddr); 59 | // this.pkg = args[0] 60 | // log.info('addr:', args[0]) 61 | // log.info('char:', args[1]) 62 | // log.info('size:', args[2]) 63 | // log.info('data:', this.pkg.readByteArray(208)) 64 | // } 65 | // catch (error) { 66 | // log.info('error:', error) 67 | // } 68 | 69 | // /* 70 | // dumpAddr('Input', args[0], args[3].toInt32()); 71 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 72 | // this.outsize = args[2].toInt32(); 73 | // */ 74 | // }, 75 | 76 | // // When function is finished 77 | // onLeave: function (retval) { 78 | // /* 79 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 80 | // log.info('[+] Returned from SomeFunc: ' + retval); 81 | // */ 82 | // log.info('data:', this.pkg.readByteArray(208)) 83 | // log.info('retval:', retval) 84 | // log.info(`onLeave\n\n`); 85 | // } 86 | // }); 87 | // } 88 | // } 89 | // { 90 | // const targetAddr = baseAddr.resolveAddress('0x00BB21C5') 91 | // if (targetAddr != null) { 92 | // const log = useLogger('MSF pre1') 93 | // Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 94 | 95 | // // When function is called, print out its parameters 96 | // /* 97 | // 以下内容演示了 98 | // 1. 怎么提取 printf 的第一个参数的字符串 99 | // 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 100 | // 其他API 用法 101 | // https://frida.re/docs/javascript-api/ 102 | // */ 103 | // onEnter: function (args) { 104 | // try { 105 | // log.info(`onEnter`); 106 | // log.info('[+] Called targetAddr:' + targetAddr); 107 | // const data = args[0] 108 | // log.info('seq:', data.add(72).readInt()) 109 | 110 | // const cmdAndData = data.add(40) 111 | // const p = cmdAndData.readPointer() 112 | // log.info('cmd:', p.readUtf8String()) 113 | 114 | // const start = p.add(32).readPointer() 115 | // const end = start.add(8) 116 | // const size = end.readPointer().sub(start.readPointer()).toInt32() 117 | // log.info('data:', start.readPointer().readByteArray(size)) 118 | // } 119 | // catch (error) { 120 | // log.info('error:', error) 121 | // } 122 | 123 | // /* 124 | // dumpAddr('Input', args[0], args[3].toInt32()); 125 | // this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 126 | // this.outsize = args[2].toInt32(); 127 | // */ 128 | // }, 129 | 130 | // // When function is finished 131 | // onLeave: function (retval) { 132 | // /* 133 | // dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 134 | // log.info('[+] Returned from SomeFunc: ' + retval); 135 | // */ 136 | // log.info('retval:', retval) 137 | // log.info(`onLeave\n\n`); 138 | // } 139 | // }); 140 | // } 141 | // } 142 | { 143 | const targetAddr = baseAddr.resolveAddress('0x01BD1DEE') 144 | if (targetAddr != null) { 145 | const log = useLogger('MSF pre') 146 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 147 | 148 | // When function is called, print out its parameters 149 | /* 150 | 以下内容演示了 151 | 1. 怎么提取 printf 的第一个参数的字符串 152 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 153 | 其他API 用法 154 | https://frida.re/docs/javascript-api/ 155 | */ 156 | onEnter: function (args) { 157 | try { 158 | log.info(`onEnter`); 159 | log.info('[+] Called targetAddr:' + targetAddr); 160 | log.info('a1:', args[0]) 161 | log.info('a2:', args[1]) 162 | log.info('a3:', args[2]) 163 | log.info('a4:', args[3]) 164 | log.info('a5:', args[4]) 165 | log.info('a6:', args[5]) 166 | log.info('a7:', args[6]) 167 | 168 | const cmdAndData = args[2] 169 | log.info(cmdAndData.readByteArray(64)) 170 | const p = cmdAndData.readPointer() 171 | log.info('cmd:', p.readUtf8String()) 172 | 173 | const start = p.add(32).readPointer() 174 | const end = start.add(8) 175 | const size = end.readPointer().sub(start.readPointer()).toInt32() 176 | log.info('data:', start.readPointer().readByteArray(size)) 177 | } 178 | catch (error) { 179 | log.info('error:', error) 180 | } 181 | 182 | /* 183 | dumpAddr('Input', args[0], args[3].toInt32()); 184 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 185 | this.outsize = args[2].toInt32(); 186 | */ 187 | }, 188 | 189 | // When function is finished 190 | onLeave: function (retval) { 191 | /* 192 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 193 | log.info('[+] Returned from SomeFunc: ' + retval); 194 | */ 195 | log.info('retval:', retval) 196 | log.info(`onLeave\n\n`); 197 | } 198 | }); 199 | } 200 | } 201 | { 202 | const targetAddr = baseAddr.resolveAddress('0x01BD19E8') 203 | if (targetAddr != null) { 204 | const log = useLogger('MSF') 205 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 206 | 207 | // When function is called, print out its parameters 208 | /* 209 | 以下内容演示了 210 | 1. 怎么提取 printf 的第一个参数的字符串 211 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 212 | 其他API 用法 213 | https://frida.re/docs/javascript-api/ 214 | */ 215 | onEnter: function (args) { 216 | try { 217 | log.info(`onEnter`); 218 | log.info('[+] Called targetAddr:' + targetAddr); 219 | const msfData = args[1].readPointer() 220 | log.info(msfData.readByteArray(208)) 221 | this.msfData = msfData 222 | const msf = new MsfParse(msfData) 223 | log.info('seq:', msf.seq) 224 | log.info('uin:', msf.uin) 225 | log.info('cmd:', msf.cmd) 226 | log.info('dataSize:', msf.dataSize) 227 | log.info('data:', msf.data) 228 | 229 | } 230 | catch (error) { 231 | log.info('error:', error) 232 | } 233 | 234 | /* 235 | dumpAddr('Input', args[0], args[3].toInt32()); 236 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 237 | this.outsize = args[2].toInt32(); 238 | */ 239 | }, 240 | 241 | // When function is finished 242 | onLeave: function (retval) { 243 | /* 244 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 245 | log.info('[+] Returned from SomeFunc: ' + retval); 246 | */ 247 | log.info(this.msfData.readByteArray(208)) 248 | log.info('retval:', retval) 249 | log.info(`onLeave\n\n`); 250 | } 251 | }); 252 | } 253 | } 254 | } -------------------------------------------------------------------------------- /agent/hook/nt/oidb/oidb.ts: -------------------------------------------------------------------------------- 1 | import BaseAddr from "../../utils/addr.js" 2 | import { hookParamParse } from "./param-parse.js" 3 | import { hookProcess } from "./process-start.js" 4 | 5 | export const hookOIDB = (baseAddr: BaseAddr) => { 6 | hookParamParse(baseAddr) 7 | hookProcess(baseAddr) 8 | } -------------------------------------------------------------------------------- /agent/hook/nt/oidb/param-parse.ts: -------------------------------------------------------------------------------- 1 | import BaseAddr from "../../utils/addr.js"; 2 | import { useLogger } from "../../../utils/log.js"; 3 | 4 | export const hookParamParse = (baseAddr: BaseAddr) => { 5 | { 6 | const targetAddr = baseAddr.resolveAddress('0x01EF0A1B') 7 | if (targetAddr != null) { 8 | const log = useLogger('ParamPaser') 9 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 10 | 11 | // When function is called, print out its parameters 12 | /* 13 | 以下内容演示了 14 | 1. 怎么提取 printf 的第一个参数的字符串 15 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 16 | 其他API 用法 17 | https://frida.re/docs/javascript-api/ 18 | */ 19 | onEnter: function (args) { 20 | try { 21 | log.info(`onEnter`); 22 | log.info('[+] Called targetAddr:' + targetAddr); 23 | } 24 | catch (error) { 25 | log.info('error:', error) 26 | } 27 | 28 | /* 29 | dumpAddr('Input', args[0], args[3].toInt32()); 30 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 31 | this.outsize = args[2].toInt32(); 32 | */ 33 | }, 34 | 35 | // When function is finished 36 | onLeave: function (retval) { 37 | /* 38 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 39 | log.info('[+] Returned from SomeFunc: ' + retval); 40 | */ 41 | log.info('retval:', retval) 42 | log.info(`onLeave\n\n`); 43 | } 44 | }); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /agent/hook/nt/oidb/process-start.ts: -------------------------------------------------------------------------------- 1 | import BaseAddr from "../../utils/addr.js"; 2 | import { useLogger } from "../../../utils/log.js"; 3 | class Buf { 4 | private p: NativePointer 5 | constructor(p: NativePointer) 6 | { 7 | this.p = p 8 | } 9 | get size() { 10 | return this.p.add(8).readPointer().sub(this.p.readPointer()).toInt32() 11 | } 12 | toString() { 13 | return this.p.readPointer().readUtf8String(this.size) 14 | } 15 | } 16 | export const hookProcess = (baseAddr: BaseAddr) => { 17 | { 18 | const targetAddr = baseAddr.resolveAddress('0x00056DE2') 19 | if (targetAddr != null) { 20 | const log = useLogger('Process1') 21 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 22 | 23 | // When function is called, print out its parameters 24 | /* 25 | 以下内容演示了 26 | 1. 怎么提取 printf 的第一个参数的字符串 27 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 28 | 其他API 用法 29 | https://frida.re/docs/javascript-api/ 30 | */ 31 | onEnter: function (args) { 32 | try { 33 | log.info(`onEnter`); 34 | log.info('[+] Called targetAddr:' + targetAddr); 35 | log.info(args[0]) 36 | log.info(args[1].toInt32()) 37 | log.info(args[2].toInt32()) 38 | log.info(args[3].toInt32()) 39 | log.info(args[4].readUtf8String()) 40 | log.info(args[5].readByteArray(16)) 41 | const buf = new Buf(args[5]) 42 | log.info('buf size:', buf.size) 43 | log.info('buf data:', buf.toString()) 44 | } 45 | catch (error) { 46 | log.info('error:', error) 47 | } 48 | 49 | /* 50 | dumpAddr('Input', args[0], args[3].toInt32()); 51 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 52 | this.outsize = args[2].toInt32(); 53 | */ 54 | }, 55 | 56 | // When function is finished 57 | onLeave: function (retval) { 58 | /* 59 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 60 | log.info('[+] Returned from SomeFunc: ' + retval); 61 | */ 62 | log.info('retval:', retval) 63 | log.info(`onLeave\n\n`); 64 | } 65 | }); 66 | } 67 | } 68 | { 69 | const targetAddr = baseAddr.resolveAddress('0x0005408A') 70 | if (targetAddr != null) { 71 | const log = useLogger('Process1 - 1') 72 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 73 | 74 | // When function is called, print out its parameters 75 | /* 76 | 以下内容演示了 77 | 1. 怎么提取 printf 的第一个参数的字符串 78 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 79 | 其他API 用法 80 | https://frida.re/docs/javascript-api/ 81 | */ 82 | onEnter: function (args) { 83 | try { 84 | log.info(`onEnter`); 85 | log.info('[+] Called targetAddr:' + targetAddr); 86 | log.info('arg0:', args[0]) 87 | log.info('arg1:', args[1].toInt32()) 88 | log.info('arg2:', args[2].toInt32()) 89 | log.info('arg3:', args[3].toInt32()) 90 | log.info('arg4:', args[4].readUtf8String()) 91 | const buf = new Buf(args[5]) 92 | log.info('buf size:', buf.size) 93 | log.info('buf data:', buf.toString()) 94 | } 95 | catch (error) { 96 | log.info('error:', error) 97 | } 98 | 99 | /* 100 | dumpAddr('Input', args[0], args[3].toInt32()); 101 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 102 | this.outsize = args[2].toInt32(); 103 | */ 104 | }, 105 | 106 | // When function is finished 107 | onLeave: function (retval) { 108 | /* 109 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 110 | log.info('[+] Returned from SomeFunc: ' + retval); 111 | */ 112 | log.info('retval:', retval) 113 | log.info(`onLeave\n\n`); 114 | } 115 | }); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /agent/hook/nt/sql-linux.ts: -------------------------------------------------------------------------------- 1 | import { StdString } from "../../cpp/std_string.js"; 2 | import BaseAddr from "../utils/addr.js"; 3 | 4 | export const hookSql = (baseAddr: BaseAddr) => { 5 | { 6 | const target = 'sql' 7 | console.log('hook sql...') 8 | const targetAddr = baseAddr.resolveAddress('0x05479350') 9 | if (targetAddr != null) { 10 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 11 | 12 | // When function is called, print out its parameters 13 | /* 14 | 以下内容演示了 15 | 1. 怎么提取 printf 的第一个参数的字符串 16 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 17 | 其他API 用法 18 | https://frida.re/docs/javascript-api/ 19 | */ 20 | onEnter: function (args) { 21 | try { 22 | console.log(`${target} - onEnter`); 23 | console.log('[+] Called targetAddr:' + targetAddr); 24 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 25 | // console.log('arg0:', readStdString(args[0])) 26 | const a1 = args[0] 27 | const a2 = args[1] 28 | const a3 = args[2] 29 | const a4 = args[3] 30 | const a5 = args[3] 31 | const a6 = args[3] 32 | 33 | console.log('args:', a1, a2, a3, a4, a5, a6) 34 | // console.log('a1:', a1.readPointer()) 35 | } 36 | catch (error) { 37 | console.log('error:', error) 38 | } 39 | 40 | /* 41 | dumpAddr('Input', args[0], args[3].toInt32()); 42 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 43 | this.outsize = args[2].toInt32(); 44 | */ 45 | }, 46 | 47 | // When function is finished 48 | onLeave: function (retval) { 49 | /* 50 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 51 | console.log('[+] Returned from SomeFunc: ' + retval); 52 | */ 53 | console.log('retval:', retval) 54 | console.log(`${target} - onLeave\n\n`); 55 | } 56 | }); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /agent/hook/nt/sqlite3_step.ts: -------------------------------------------------------------------------------- 1 | import { useLogger } from "../../utils/log.js"; 2 | import BaseAddr from "../utils/addr.js"; 3 | 4 | class Vdbe { 5 | private p: NativePointer 6 | constructor(p: NativePointer) 7 | { 8 | this.p = p 9 | } 10 | get nResColumn() { 11 | return this.p.add(200).readU16() 12 | } 13 | get zSql() { 14 | return this.p.add(264).readPointer().readUtf8String() 15 | } 16 | } 17 | export const hookSqlite3Step = (baseAddr: BaseAddr) => { 18 | { 19 | const targetAddr = baseAddr.resolveAddress('0x00D9CCF0') 20 | if (targetAddr != null) { 21 | const log = useLogger('Sqlite3Step') 22 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 23 | 24 | // When function is called, print out its parameters 25 | /* 26 | 以下内容演示了 27 | 1. 怎么提取 printf 的第一个参数的字符串 28 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 29 | 其他API 用法 30 | https://frida.re/docs/javascript-api/ 31 | */ 32 | onEnter: function (args) { 33 | try { 34 | log.info(`onEnter`); 35 | log.info('[+] Called targetAddr:' + targetAddr); 36 | const p = args[0] 37 | const vdbe = new Vdbe(p) 38 | log.info(p.readByteArray(320)) 39 | log.info('nResColumn:', vdbe.nResColumn) 40 | log.info('zSql:', vdbe.zSql) 41 | } 42 | catch (error) { 43 | log.info('error:', error) 44 | } 45 | 46 | /* 47 | dumpAddr('Input', args[0], args[3].toInt32()); 48 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 49 | this.outsize = args[2].toInt32(); 50 | */ 51 | }, 52 | 53 | // When function is finished 54 | onLeave: function (retval) { 55 | /* 56 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 57 | log.info('[+] Returned from SomeFunc: ' + retval); 58 | */ 59 | log.info('retval:', retval.toInt32()) 60 | log.info(`onLeave\n\n`); 61 | } 62 | }); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /agent/hook/utils/addr.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export default class BaseAddr { 4 | private baseAddr 5 | private type: 'wrapper' 6 | private idaBaseMap: Record<'wrapper', string> = { 7 | // section virtual address - Offset to raw data for section 8 | // 0x1000 - 0x400 待验证 9 | wrapper: '0x000C00' 10 | } 11 | constructor(type: 'wrapper', baseAddr: NativePointer) { 12 | this.baseAddr = baseAddr 13 | this.type = type 14 | } 15 | resolveAddress(addr: string) { 16 | if (this.baseAddr == null) 17 | throw new Error('baseAddr error!') 18 | var result; 19 | try { 20 | var idaBase = ptr(this.idaBaseMap[this.type]); // Enter the base address of jvm.dll as seen in your favorite disassembler (here IDA) 21 | var offset = ptr(addr).add(idaBase); // Calculate offset in memory from base address in IDA database 22 | result = this.baseAddr.add(offset); // Add current memory base address to offset of function to monitor 23 | console.log('[+] New addr=' + result); // Write location of function in memory to console 24 | } catch (error) { 25 | console.log(error) 26 | } 27 | return result; 28 | } 29 | } -------------------------------------------------------------------------------- /agent/hook/utils/file.ts: -------------------------------------------------------------------------------- 1 | 2 | import BaseAddr from "./addr.js" 3 | 4 | export const hookReadFile = (baseAddr: BaseAddr) => { 5 | 6 | { 7 | // ReadFile(char *FileName, int a2) 8 | let fileContentPtr: NativePointer | null 9 | const targetAddr = baseAddr.resolveAddress('0x11fe480') 10 | // ReadFile 11 | if (targetAddr != null) { 12 | Interceptor.attach(targetAddr, { // Intercept calls to our SetAesDecrypt function 13 | 14 | // When function is called, print out its parameters 15 | /* 16 | 以下内容演示了 17 | 1. 怎么提取 printf 的第一个参数的字符串 18 | 2. 怎么结合 onLever 做进入函数的时候获取 该函数要操作的内存和长度 ,等函数工作完毕,提取该数据 19 | 其他API 用法 20 | https://frida.re/docs/javascript-api/ 21 | */ 22 | onEnter: function (args) { 23 | try { 24 | 25 | console.log('ReadFile - onEnter'); 26 | console.log('[+] Called targetAddr:' + targetAddr); 27 | // console.log('[+] Ctx: ' + args[-1]); 28 | // console.log('[+] FormatString: ' + Memory.readAnsiString(args[0])); // Plaintext 29 | // console.log('arg0:', readStdString(args[0])) 30 | console.log('[+] Argv0: ', args[0]) 31 | console.log('[+] Argv1: ' + args[1]); // This pointer will store the de/encrypted data 32 | fileContentPtr = args[1] 33 | // console.log('[+] Argv2: ' + args[2]); // Length of data to en/decrypt 34 | // console.log('[+] Argv3: ' + args[3]); // Length of data to en/decrypt 35 | // const stdString = args[0] 36 | // console.log(stdString.add(0 * Process.pointerSize).readPointer()) 37 | // console.log(stdString.add(1 * Process.pointerSize).readPointer()) 38 | // console.log(stdString.add(2 * Process.pointerSize).readPointer()) 39 | // console.log(stdString.add(3 * Process.pointerSize).readPointer()) 40 | // console.log('[*] Intercepted printRef() with string length:', StdString.length(args[0])); 41 | console.log('arg0:', args[0].readUtf8String()) 42 | // console.log('test read:', readStdString(ptr('0x00f7fcf0'))) 43 | } catch (error) { 44 | console.log('error:', error) 45 | } 46 | 47 | /* 48 | dumpAddr('Input', args[0], args[3].toInt32()); 49 | this.outptr = args[1]; // Store arg2 and arg3 in order to see when we leave the function 50 | this.outsize = args[2].toInt32(); 51 | */ 52 | }, 53 | 54 | // When function is finished 55 | onLeave: function (retval) { 56 | /* 57 | dumpAddr('Output', this.outptr, this.outsize); // Print out data array, which will contain de/encrypted data as output 58 | console.log('[+] Returned from SomeFunc: ' + retval); 59 | */ 60 | console.log('prt:', fileContentPtr) 61 | } 62 | }); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /agent/index.ts: -------------------------------------------------------------------------------- 1 | import { log } from "./logger.js" 2 | import BaseAddr from "./hook/utils/addr.js" 3 | import { hook } from "./hook/index.js" 4 | import { readMap } from "./utils/map.js" 5 | 6 | (() => { 7 | const type = 'wrapper' 8 | const moduleName = 'wrapper-1.node' 9 | const _baseAddr = Module.findBaseAddress(moduleName); 10 | if (_baseAddr == null) 11 | throw new Error(`baseAddr error! ${moduleName}`) 12 | console.log('base addr:', _baseAddr) 13 | const baseAddr = new BaseAddr(type, _baseAddr) 14 | console.log('start hook') 15 | hook(baseAddr) 16 | })() -------------------------------------------------------------------------------- /agent/logger.ts: -------------------------------------------------------------------------------- 1 | export function log(message: string): void { 2 | console.log(message); 3 | } 4 | -------------------------------------------------------------------------------- /agent/utils/log.ts: -------------------------------------------------------------------------------- 1 | 2 | const enum LogLevel { 3 | /** 追踪日志 */ 4 | Trace, 5 | Debug, 6 | /** 警告日志 */ 7 | /** 普通日志 */ 8 | Info, 9 | /** 调试日志 */ 10 | Warning, 11 | /** 错误日志 */ 12 | Error, 13 | } 14 | const _console = { 15 | debug: console.debug, 16 | info: console.info, 17 | warn: console.warn, 18 | error: console.error, 19 | trace: console.trace, 20 | } 21 | const color = { 22 | red: 31, 23 | green: 32, 24 | yellow: 33, 25 | blue: 34, 26 | white: 37, 27 | } 28 | const Styles = [ 29 | `\x1b[${color.white}m%s\x1b[0m`, 30 | `\x1b[${color.blue}m%s\x1b[0m`, 31 | `\x1b[${color.green}m%s\x1b[0m`, 32 | `\x1b[${color.yellow}m%s\x1b[0m`, 33 | `\x1b[${color.red}m%s\x1b[0m` 34 | ] 35 | const Methods = [ 36 | 'trace', 37 | 'debug', 38 | 'info', 39 | 'warn', 40 | 'error' 41 | ] as const 42 | /** 43 | * 日志的配置类型 44 | */ 45 | interface LoggerConfigType { 46 | /** 命名空间 */ 47 | namespace: string 48 | } 49 | /** 50 | * 拦截器函数类型 51 | */ 52 | type InterceptorFuncType = (config: LoggerConfigType) => void 53 | 54 | const isLogEnabled = true 55 | 56 | if (!isLogEnabled) { 57 | _console.info('================================日志打印已关闭!=======================================') 58 | } 59 | 60 | const CurrentLogLevel: LogLevel = LogLevel.Trace 61 | 62 | /** 63 | * 日志打印工具,统一管理日志输出&上报 64 | */ 65 | class Logger { 66 | /** 命名空间(scope),用于区分所在执行文件 */ 67 | private readonly beforeFuncs: InterceptorFuncType[] = [] 68 | private readonly afterFuncs: InterceptorFuncType[] = [] 69 | private readonly config: LoggerConfigType = { 70 | namespace: '', 71 | } 72 | 73 | constructor (namespace = 'unknown') { 74 | this.config.namespace = `[${namespace}]` 75 | } 76 | 77 | /** 78 | * 创建新的 Logger 实例 79 | * 80 | * @param namespace 命名空间 81 | * @returns Logger 82 | */ 83 | public create (namespace = 'unknown') { 84 | return new Logger(namespace) 85 | } 86 | 87 | private _log (level: LogLevel, args: unknown[]) { 88 | if (!isLogEnabled) return 89 | // 优先级小的不显示 90 | if (level < CurrentLogLevel) return 91 | this.beforeFuncs.forEach(e => e(this.config)) 92 | const now = new Date() 93 | const fix = (d: number, len = 2) => (d + '').padStart(len, '0') 94 | const time = `${now.getFullYear()}-${fix(now.getMonth() + 1)}-${fix(now.getDate())} ${fix(now.getHours())}:${fix(now.getMinutes())}:${fix(now.getSeconds())}.${fix(now.getMilliseconds(), 3)}` 95 | _console[Methods[level]](`[${time}] [${Styles[level]}] ${this.config.namespace}`, Methods[level], ...args) 96 | this.afterFuncs.forEach(e => e(this.config)) 97 | } 98 | 99 | /** 100 | * 添加拦截器 101 | * @param func 拦截器 102 | * @param isBefore 是否日志之前 103 | * @returns this 104 | */ 105 | public addInterceptor (func: InterceptorFuncType, isBefore = true) { 106 | if (typeof func !== 'function') 107 | return this.error('拦截器函数不符合规范') 108 | if (isBefore) { 109 | this.beforeFuncs.push(func) 110 | return this 111 | } 112 | this.afterFuncs.push(func) 113 | return this 114 | } 115 | 116 | /** 117 | * 添加日志打印之前的拦截函数 118 | * 119 | * @param func 拦截器 120 | * @returns this 121 | */ 122 | public addBeforeInterceptor (func: InterceptorFuncType) { 123 | this.beforeFuncs.push(func) 124 | return this 125 | } 126 | 127 | /** 128 | * 添加日志打印之后的拦截函数 129 | * 130 | * @param func 拦截器 131 | * @returns this 132 | */ 133 | public addAfterInterceptor (func: InterceptorFuncType) { 134 | this.afterFuncs.push(func) 135 | return this 136 | } 137 | 138 | /** 139 | * 打印追踪信息 🐛 140 | * 141 | * @param args 任意参数 142 | */ 143 | public trace (...args: unknown[]) { 144 | this._log(LogLevel.Trace, args) 145 | return this 146 | } 147 | 148 | /** 149 | * 打印调试信息 🐛 150 | * 151 | * @param args 任意参数 152 | */ 153 | public debug (...args: unknown[]) { 154 | this._log(LogLevel.Info, args) 155 | return this 156 | } 157 | 158 | /** 159 | * 打印输出信息 🐛 160 | * 161 | * @param args 任意参数 162 | */ 163 | public info (...args: unknown[]) { 164 | this._log(LogLevel.Info, args) 165 | return this 166 | } 167 | 168 | /** 169 | * 打印输出警告信息 ❕ 170 | * 171 | * @param args 任意参数 172 | */ 173 | public warn (...args: unknown[]) { 174 | this._log(LogLevel.Warning, args) 175 | return this 176 | } 177 | 178 | /** 179 | * 打印输出错误信息 ❌ 180 | * 181 | * @param args 任意参数 182 | */ 183 | public error (...args: unknown[]) { 184 | this._log(LogLevel.Error, args) 185 | return this 186 | } 187 | 188 | /** 189 | * 设置命名空间(日志前缀) 190 | * @param namespace 191 | */ 192 | public setNamespace (namespace = '') { 193 | this.config.namespace = `[${namespace}]` 194 | return this 195 | } 196 | } 197 | 198 | // export const nanoLog = new Logger() 199 | 200 | export const useLogger = (namespace?: string) => { 201 | return new Logger(namespace) 202 | } 203 | -------------------------------------------------------------------------------- /agent/utils/map.ts: -------------------------------------------------------------------------------- 1 | import { readFileSync } from "fs" 2 | import * as path from "path" 3 | import map from '../../addr_map/map.js' 4 | export const readMap = (type: 'wcc' | 'wcsc') => { 5 | return map[type] 6 | // return {} 7 | } -------------------------------------------------------------------------------- /hook.js: -------------------------------------------------------------------------------- 1 | console.log(__dirname) -------------------------------------------------------------------------------- /hook.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import frida 3 | 4 | 5 | 6 | # jscode = ''' 7 | # Java.perform(function() { 8 | # var CoolMarket = Java.use('com.coolapk.market.CoolMarketApplication'); 9 | # CoolMarket.onLog.implementation = function() { 10 | 11 | # var deviceId = Java.use('com.coolapk.market.util.SystemUtils').getDeviceId(this); 12 | # console.log('Device Id: ', deviceId); 13 | 14 | # var app_token = Java.use('com.coolapk.market.util.AuthUtils').getAS(this, deviceId); 15 | # console.log('App Token: ', app_token); 16 | 17 | # console.log('----------'); 18 | # return 1; 19 | # } 20 | # }) 21 | # ''' 22 | 23 | 24 | jscodes = ''' 25 | Java.perform(function() { 26 | var load_pointer = Module.getExportByName('libnative-lib.so', 'JNI_OnLoad'); 27 | var hook_pointer = '0x' + parseInt(parseInt(load_pointer) - parseInt('0x31A04') + parseInt('0x31DB8')).toString(16); 28 | var pointer = new NativePointer(hook_pointer); 29 | console.log('Hook Method Pointer: ', pointer); 30 | 31 | var b64_encode = new NativeFunction(pointer, 'pointer', ['uchar', 'uint']); 32 | 33 | Interceptor.attach(pointer, { 34 | onEnter: function(args) { 35 | console.log('===> method hooked.'); 36 | console.log(Memory.readCString(args[0])); 37 | console.log(args[1].toInt32()); 38 | console.log('---'); 39 | }, 40 | onLeave: function(retval) { 41 | console.log(Memory.readCString(retval)); 42 | } 43 | }); 44 | }) 45 | ''' 46 | 47 | def on_message(message, data): 48 | print("[%s] => %s" % (message, data)) 49 | 50 | if __name__ == '__main__': 51 | jscode = open('hook.js', 'r',encoding='utf-8').read() 52 | process = frida.attach('main.exe') 53 | script = process.create_script(jscode) 54 | script.on('message', on_message) 55 | print('[*] Running CTF') 56 | script.load() 57 | sys.stdin.read() 58 | # print('api.hello() =>', script.exports.hello()) 59 | process.detach() -------------------------------------------------------------------------------- /nt.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require("child_process"); 2 | const fs = require('fs'); 3 | (async () => { 4 | console.log('start') 5 | const hookTask = spawn('python', ['-u', ".\\nt.py"], { 6 | 7 | }) 8 | // const f = fs.openSync('output.log', 'w') 9 | hookTask.stdout.on('data', (d) => { 10 | process.stdout.write(d) 11 | // fs.writeSync(f, d.toString()) 12 | }) 13 | // console.log('end') 14 | hookTask.on('exit', () => { 15 | // fs.closeSync(f) 16 | }) 17 | 18 | })() -------------------------------------------------------------------------------- /nt.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import frida 3 | import psutil 4 | 5 | PROCESS_NAME = "QQ.exe" 6 | print("PROCESS_NAME:", PROCESS_NAME) 7 | # qq 8 | QQ_PID = None 9 | # GUI -> ['C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe'] 10 | # 要hook的 -> ['C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe', '/hosthwnd=2164594', '/hostname=QQ_IPC_{12345678-ABCD-12EF-9976-18373DEAB821}', '/memoryid=0', 'C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe'] 11 | 12 | process_list = [] 13 | for pid in psutil.pids(): 14 | # print(pid) 15 | try: 16 | p = psutil.Process(pid) 17 | # QQ.exe and len(p.cmdline()) > 1 18 | # and len(p.cmdline()) == 1 19 | if p.name() == PROCESS_NAME and len(p.cmdline()) == 1: 20 | print(p.cmdline()) 21 | process_list.append(p) 22 | del p 23 | break 24 | except Exception: 25 | print('error next') 26 | 27 | print("QQ pids count:", len(process_list)) 28 | if len(process_list) == 1: 29 | QQ_PID = process_list[0].pid 30 | # QQ_PID = 40360 31 | if QQ_PID is None: 32 | print("QQ not launched. exit.") 33 | sys.exit(1) 34 | print("QQ pid is:", QQ_PID) 35 | 36 | # jscode = ''' 37 | # Java.perform(function() { 38 | # var CoolMarket = Java.use('com.coolapk.market.CoolMarketApplication'); 39 | # CoolMarket.onLog.implementation = function() { 40 | 41 | # var deviceId = Java.use('com.coolapk.market.util.SystemUtils').getDeviceId(this); 42 | # console.log('Device Id: ', deviceId); 43 | 44 | # var app_token = Java.use('com.coolapk.market.util.AuthUtils').getAS(this, deviceId); 45 | # console.log('App Token: ', app_token); 46 | 47 | # console.log('----------'); 48 | # return 1; 49 | # } 50 | # }) 51 | # ''' 52 | 53 | 54 | jscodes = ''' 55 | Java.perform(function() { 56 | var load_pointer = Module.getExportByName('libnative-lib.so', 'JNI_OnLoad'); 57 | var hook_pointer = '0x' + parseInt(parseInt(load_pointer) - parseInt('0x31A04') + parseInt('0x31DB8')).toString(16); 58 | var pointer = new NativePointer(hook_pointer); 59 | console.log('Hook Method Pointer: ', pointer); 60 | 61 | var b64_encode = new NativeFunction(pointer, 'pointer', ['uchar', 'uint']); 62 | 63 | Interceptor.attach(pointer, { 64 | onEnter: function(args) { 65 | console.log('===> method hooked.'); 66 | console.log(Memory.readCString(args[0])); 67 | console.log(args[1].toInt32()); 68 | console.log('---'); 69 | }, 70 | onLeave: function(retval) { 71 | console.log(Memory.readCString(retval)); 72 | } 73 | }); 74 | }) 75 | ''' 76 | 77 | def on_message(message, data): 78 | print("[%s] => %s" % (message, data)) 79 | 80 | def on_destroyed(): 81 | print("process exited.") 82 | sys.exit(0) 83 | 84 | if __name__ == '__main__': 85 | jscode = open('_agent.js', 'r',encoding='utf-8').read() 86 | print("attach") 87 | process = frida.attach(QQ_PID) 88 | script = process.create_script(jscode) 89 | script.on('message', on_message) 90 | script.on('destroyed', on_destroyed) 91 | print('[*] Running CTF') 92 | script.load() 93 | sys.stdin.readline() 94 | # print('api.hello() =>', script.exports.hello()) 95 | process.detach() -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frida-agent-example", 3 | "version": "1.0.0", 4 | "description": "Example Frida agent written in TypeScript", 5 | "private": true, 6 | "main": "agent/index.ts", 7 | "scripts": { 8 | "prepare": "npm run build", 9 | "build": "frida-compile agent/index.ts -o _agent.js -c", 10 | "watch": "frida-compile agent/index.ts -o _agent.js -w", 11 | "hook-nt": "node nt.js > output.log", 12 | "hook-py": "python -u nt.py", 13 | "hook-py-log": "python -u nt.py > output.log" 14 | }, 15 | "devDependencies": { 16 | "@types/frida-gum": "^18.3.2", 17 | "@types/node": "^20.3.1", 18 | "eslint-config-airbnb-base": "^15.0.0", 19 | "eslint-import-resolver-alias": "^1.1.2", 20 | "eslint-plugin-import": "^2.27.5", 21 | "frida-compile": "^16.3.0" 22 | }, 23 | "packageManager": "pnpm@9.11.0+sha512.0a203ffaed5a3f63242cd064c8fb5892366c103e328079318f78062f24ea8c9d50bc6a47aa3567cabefd824d170e78fa2745ed1f16b132e16436146b7688f19b" 24 | } 25 | -------------------------------------------------------------------------------- /pcqq_get_key.py: -------------------------------------------------------------------------------- 1 | import frida 2 | import sys 3 | import psutil 4 | 5 | QQ_PID = None 6 | # GUI -> ['C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe'] 7 | # 要hook的 -> ['C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe', '/hosthwnd=2164594', '/hostname=QQ_IPC_{12345678-ABCD-12EF-9976-18373DEAB821}', '/memoryid=0', 'C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQ.exe'] 8 | for pid in psutil.pids(): 9 | p = psutil.Process(pid) 10 | if p.name() == "QQ.exe" and len(p.cmdline()) > 1: 11 | QQ_PID = pid 12 | del p 13 | break 14 | 15 | if QQ_PID is None: 16 | print("QQ not launched. exit.") 17 | sys.exit(1) 18 | print("QQ pid is:", QQ_PID) 19 | demo_script = """ 20 | var pMessageBoxW = Module.findExportByName("user32.dll", 'MessageBoxA') 21 | var lpText = Memory.allocAnsiString("I'm New MessageBox"); 22 | var funMsgBox = new NativeFunction(pMessageBoxW, 'uint32',['uint32','pointer','pointer','uint32']); 23 | 24 | funMsgBox(0, ptr(lpText), ptr(lpText), 0); 25 | """ 26 | hook_script = """ 27 | function buf2hex(buffer) { 28 | const byteArray = new Uint8Array(buffer); 29 | const hexParts = []; 30 | for(let i = 0; i < byteArray.length; i++) { 31 | const hex = byteArray[i].toString(16); 32 | const paddedHex = ('00' + hex).slice(-2); 33 | hexParts.push(paddedHex); 34 | } 35 | return '0x' + hexParts.join(', 0x'); 36 | } 37 | 38 | const kernel_util = Module.load('KernelUtil.dll'); 39 | function single_function(pattern) { 40 | pattern = pattern.replaceAll("##", "").replaceAll(" ", "").toLowerCase().replace(/\\s/g,'').replace(/(.{2})/g,"$1 "); 41 | var akey_function_list = Memory.scanSync(kernel_util.base, kernel_util.size, pattern); 42 | if (akey_function_list.length > 1) { 43 | send("pattern FOUND MULTI!!") 44 | send(pattern) 45 | send(akey_function_list) 46 | send("!!exit") 47 | } 48 | if (akey_function_list.length == 0) { 49 | send("pattern NOT FOUND!!") 50 | send("!!exit") 51 | } 52 | return akey_function_list[0]['address']; 53 | } 54 | 55 | // const key_function = Module.findExportByName("KernelUtil.dll", 'sqlite3_key') 56 | const key_function = single_function("55 8b ec 56 6b 75 10 11 83 7d 10 10 74 0d 68 17 02 00 00 e8") 57 | const name_function = single_function("55 8B EC FF 75 0C FF 75 08 E8 B8 D1 02 00 59 59 85") 58 | // send(key_function) 59 | var funcName = new NativeFunction(name_function, 'pointer', ['pointer', 'pointer']); 60 | 61 | 62 | Interceptor.attach(key_function, { 63 | onEnter: function (args, state) { 64 | 65 | console.log("[+] key found:"); 66 | var dbName = funcName(args[0], NULL).readUtf8String(); 67 | if (dbName.replaceAll('/', '\\\\').split('\\\\').pop().toLowerCase() == 'Msg3.0.db'.toLowerCase() || false) { 68 | //console.log("¦- db: " + args[0]); 69 | console.log("¦- nKey: " + args[2].toInt32()); 70 | //console.log("¦- pkey: " + args[1]); 71 | console.log("¦- *pkey: " + buf2hex(args[1].readByteArray(args[2].toInt32()))); 72 | console.log("¦- dbName: " + funcName(args[0], NULL).readUtf8String()); 73 | //console.log("¦- *pkey: " + buf2hex(Memory.readByteArray(new UInt64(args[1]), args[2]))); 74 | } 75 | }, 76 | 77 | onLeave: function (retval, state) { 78 | } 79 | 80 | }); 81 | """ 82 | 83 | session = frida.get_local_device().attach(QQ_PID) 84 | script = session.create_script(hook_script) 85 | 86 | def on_message(message, data): 87 | if message['type'] == 'send': 88 | if message['payload'] == "!!exit": 89 | exit(3) 90 | print(message['payload']) 91 | elif message['type'] == 'error': 92 | print(message['stack']) 93 | 94 | def on_destroyed(): 95 | print("process exited.") 96 | sys.exit(0) 97 | 98 | script.on('message', on_message) 99 | script.on('destroyed', on_destroyed) 100 | script.load() 101 | print("hooked.") 102 | sys.stdin.read() -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@types/frida-gum': 12 | specifier: ^18.3.2 13 | version: 18.3.2 14 | '@types/node': 15 | specifier: ^20.3.1 16 | version: 20.3.1 17 | eslint-config-airbnb-base: 18 | specifier: ^15.0.0 19 | version: 15.0.0(eslint-plugin-import@2.27.5(eslint@8.43.0))(eslint@8.43.0) 20 | eslint-import-resolver-alias: 21 | specifier: ^1.1.2 22 | version: 1.1.2(eslint-plugin-import@2.27.5(eslint@8.43.0)) 23 | eslint-plugin-import: 24 | specifier: ^2.27.5 25 | version: 2.27.5(eslint@8.43.0) 26 | frida-compile: 27 | specifier: ^16.3.0 28 | version: 16.3.0 29 | 30 | packages: 31 | 32 | '@eslint-community/eslint-utils@4.4.0': 33 | resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} 34 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 35 | peerDependencies: 36 | eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 37 | 38 | '@eslint-community/regexpp@4.5.1': 39 | resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==} 40 | engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} 41 | 42 | '@eslint/eslintrc@2.0.3': 43 | resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==} 44 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 45 | 46 | '@eslint/js@8.43.0': 47 | resolution: {integrity: sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==} 48 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 49 | 50 | '@frida/assert@3.0.2': 51 | resolution: {integrity: sha512-JXJq5SbXGrM5EkjrZKfRmB29zOoEOix02NC6A5TSJ+C1GE/X051EinJJsuOO2pEOx7KZwpvAHvS0WXW0+levKg==} 52 | 53 | '@frida/base64-js@2.0.3': 54 | resolution: {integrity: sha512-2w0F+1TynOTCZ/v7du9LdHPWwq0lJhazjo2fF9upMyQmA1zHetT14fLuQ1v/6T0qPgyeEGkiSrybstU8EsgeUA==} 55 | 56 | '@frida/buffer@7.0.4': 57 | resolution: {integrity: sha512-RxQ1lZRRiCJj7nhcCiD8xeJx0NsLpGGnjqsmTg7jShGmbnVFMN5W7+J+3gqdPSQhc/IxNBIWc6zRXVp4+qnYHg==} 58 | 59 | '@frida/crosspath@3.0.0': 60 | resolution: {integrity: sha512-bNdO1spIPD2P40XtK89N49oZpJhstdlnkJZcD4yJ17jrdkm9Ctu0sd9MIEX6Z8Tm8ydhVJBAOMEKl9/R27onAQ==} 61 | engines: {node: '>=14.9.0'} 62 | 63 | '@frida/diagnostics_channel@1.0.0': 64 | resolution: {integrity: sha512-mYX1jp/5Bpk24tHArJNx65iCk7qSuV8YJkdU0gFNVtJUXxfV8BG5WuPa4mL+ynxsbWWpsg/cwKZbLAepYKTdQQ==} 65 | 66 | '@frida/events@4.0.4': 67 | resolution: {integrity: sha512-qJVQ6VWHf9sjUKuiJzoCAC00frbpcwxeYfvQ+PP9LU/d70j+QvjWgYe98Qa3ekLaBU6r/AvWm8ThKCDUCLWrQQ==} 68 | engines: {node: '>=0.8.x'} 69 | 70 | '@frida/http-parser-js@1.0.0': 71 | resolution: {integrity: sha512-2nMrNXt/OeTlWbqnE8AH4Sfz4I2+BGoN206dzKEyC/g2svtn83Xu+zuv/V3TkwrA27s26Mcy84ZwsXeNlqNxUQ==} 72 | 73 | '@frida/http@4.0.2': 74 | resolution: {integrity: sha512-cvkc7ex7GmVXVOWqtjXKBWUUbYEBgpNRKZbEEoMeI8KiIs8zejKwg+N7rx7296Ao+EP3+xcUr4wBVr3xLaUVfQ==} 75 | 76 | '@frida/https@1.0.0': 77 | resolution: {integrity: sha512-OiqQ6qsALcWOktRLq07oJ0i6sH8eX6MXb/MdZS1qVKDRf6wchH4Pjn6fiLB+pt/OlYbggk+DOfpHwSdjTwuHMQ==} 78 | 79 | '@frida/ieee754@2.0.2': 80 | resolution: {integrity: sha512-wlcUebnne4ENN7GDr5pTH598ZDLMVOsh0FjenxeVOe6u7ewZkz9gGRnLnZKJAm9kl5G6XhdxhI0cSXVQK/rQUw==} 81 | 82 | '@frida/net@4.0.2': 83 | resolution: {integrity: sha512-qQRe7hQ+ZfCcG/SE3P1TRqQ9bmuK/T7wPCYaT4z56rBPWAxsaQbQHpX4fR6OrFaSDr7X0xJLsTbdIp9hGhhLZg==} 84 | 85 | '@frida/os@1.0.2': 86 | resolution: {integrity: sha512-3ISAiGNiyIya3QN2EHBCz1wqP0enTdSxP99wUeroeh8+AQRmgoOr/5TRnrVry8pe378anay3fmV/tdUMMSkehQ==} 87 | 88 | '@frida/path@2.0.3': 89 | resolution: {integrity: sha512-2RQy36QatoC846fzBhBhV8sXMsSOBGoYvwTHeaE1zUdz7F4RNScP4QEekTTooBYWYX/XjiF36KQpYAzc9OYFtg==} 90 | 91 | '@frida/process@1.2.1': 92 | resolution: {integrity: sha512-nvCu22DstFW2ttGFtOKekHM7vnjbZm+XgtvavOt427GNT6uV7k0JYK9tnMbcLMRWv57DG6udAmuJlWs8Paq1ag==} 93 | 94 | '@frida/punycode@3.0.0': 95 | resolution: {integrity: sha512-XVSDY2KamDs1D5/fTVgHcOSNxdU4kTboxzqJMBbTjcQC7XScIT9c0EfbwKCq7Kci6gWQdsHSCr7lU+9Oc4KAdg==} 96 | 97 | '@frida/querystring@1.0.0': 98 | resolution: {integrity: sha512-15m1fOZPmoO/vWlgPJrG/J9/BJDz6a2/JpVGpS8ynNzo+fBhTznaStX5nHxUs24mVTqh/OqLo0EiYJM5WWHXxg==} 99 | 100 | '@frida/readable-stream@4.1.3': 101 | resolution: {integrity: sha512-ntGUFmi+CryRGRJIK13a/VST2Ad19uivbln8Xd92vKPAARq+6vMIASDyZIqyl5BLRccfiyCHdYgrgQ6RI5rUig==} 102 | 103 | '@frida/reserved-words@1.0.0': 104 | resolution: {integrity: sha512-2yG/XxJlsGlk/mm6eZTb4OAaQEhkTI2qaFfZFtAsrA/XuCpuMWkS4y/guyBlsRu4hAuhK2HPmNM8+OLLK1zM9Q==} 105 | 106 | '@frida/stream@1.0.2': 107 | resolution: {integrity: sha512-4OuaC1ztmEKgTq3WeBhsy8Oq+AwW9n9cYnvLklcC9jwD93AEwgbWpecLlxJCVuALvTMdhKPg0nQVfyGYP/i9Bw==} 108 | 109 | '@frida/string_decoder@2.0.0': 110 | resolution: {integrity: sha512-in371tYZMHQiW9HF5MS3JDw6Ao6tyBoq34UWy2rzOswYyMG1rpizh85ofi/yVkxDiaqybEZefxzkVittpPGT6g==} 111 | 112 | '@frida/terser@1.0.0': 113 | resolution: {integrity: sha512-59h9WuNzD1Rx/zwoWqQ/FW/4Y/Q3R91Eng2hEwdHapqiTDvtKbZ08F6CynCR7ZVinrh4tLYsF46AtVPTz1ys9g==} 114 | engines: {node: '>=10'} 115 | hasBin: true 116 | 117 | '@frida/timers@3.0.0': 118 | resolution: {integrity: sha512-3b+0igv10aT8TMxefrTAd06rActqbxJLY2Xkkq9vYcPBffB/yHszl0NYIp/5ko8WC3ecDYPU6bQiY6fjs72zTA==} 119 | 120 | '@frida/tty@1.0.0': 121 | resolution: {integrity: sha512-p/kjLnKYxEAB1MdYP8+5rKv9CsHzyA+0jg9BcGETzjQVKHHcroHDULRxDYUh+DC7qs6cpX8QdDQh9E+a6ydgsQ==} 122 | 123 | '@frida/url@1.0.2': 124 | resolution: {integrity: sha512-ZKunbKJHMr8w2Eb/5K1avy0MzK1B998S17wYXNv3RmzBGxMm8S5T0F3qEpRxkU7/72P8m4izyQU87fWl+FjQsQ==} 125 | 126 | '@frida/util@1.0.3': 127 | resolution: {integrity: sha512-htcG3uDiRXv89ERVNNYhfase39kJ2X75ZARfrYcYEtJLFEsSk0nemM1YnEIR4CjrHvdvkWHrwgKkS+acOyoNEg==} 128 | 129 | '@frida/vm@2.0.0': 130 | resolution: {integrity: sha512-7fsjLWscZT5odNIBtg6qbLNI+vAk1xmii6H5W2kaYkMYt0vRohQEcDSUWacA+eaWlu5SvMjZI82Yibj/3G9pJw==} 131 | 132 | '@humanwhocodes/config-array@0.11.10': 133 | resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} 134 | engines: {node: '>=10.10.0'} 135 | deprecated: Use @eslint/config-array instead 136 | 137 | '@humanwhocodes/module-importer@1.0.1': 138 | resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} 139 | engines: {node: '>=12.22'} 140 | 141 | '@humanwhocodes/object-schema@1.2.1': 142 | resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} 143 | deprecated: Use @eslint/object-schema instead 144 | 145 | '@jridgewell/gen-mapping@0.3.3': 146 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 147 | engines: {node: '>=6.0.0'} 148 | 149 | '@jridgewell/resolve-uri@3.1.0': 150 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 151 | engines: {node: '>=6.0.0'} 152 | 153 | '@jridgewell/set-array@1.1.2': 154 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 155 | engines: {node: '>=6.0.0'} 156 | 157 | '@jridgewell/source-map@0.3.3': 158 | resolution: {integrity: sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==} 159 | 160 | '@jridgewell/sourcemap-codec@1.4.14': 161 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 162 | 163 | '@jridgewell/sourcemap-codec@1.4.15': 164 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 165 | 166 | '@jridgewell/trace-mapping@0.3.18': 167 | resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} 168 | 169 | '@nodelib/fs.scandir@2.1.5': 170 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 171 | engines: {node: '>= 8'} 172 | 173 | '@nodelib/fs.stat@2.0.5': 174 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 175 | engines: {node: '>= 8'} 176 | 177 | '@nodelib/fs.walk@1.2.8': 178 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 179 | engines: {node: '>= 8'} 180 | 181 | '@types/frida-gum@18.3.2': 182 | resolution: {integrity: sha512-bso8bJRxrhchNRrOMmT18st/THIdjzxFdcMtJ/gGSYSknJeerQ8ArBwBtlWt/f3pqVVs1Mz1Fg6lvUdjXswa+g==} 183 | 184 | '@types/json5@0.0.29': 185 | resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} 186 | 187 | '@types/node@17.0.45': 188 | resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} 189 | 190 | '@types/node@20.3.1': 191 | resolution: {integrity: sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==} 192 | 193 | acorn-jsx@5.3.2: 194 | resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} 195 | peerDependencies: 196 | acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 197 | 198 | acorn@8.9.0: 199 | resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} 200 | engines: {node: '>=0.4.0'} 201 | hasBin: true 202 | 203 | ajv@6.12.6: 204 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 205 | 206 | ansi-regex@5.0.1: 207 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 208 | engines: {node: '>=8'} 209 | 210 | ansi-styles@4.3.0: 211 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 212 | engines: {node: '>=8'} 213 | 214 | argparse@2.0.1: 215 | resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} 216 | 217 | array-buffer-byte-length@1.0.0: 218 | resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} 219 | 220 | array-includes@3.1.6: 221 | resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} 222 | engines: {node: '>= 0.4'} 223 | 224 | array.prototype.flat@1.3.1: 225 | resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} 226 | engines: {node: '>= 0.4'} 227 | 228 | array.prototype.flatmap@1.3.1: 229 | resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} 230 | engines: {node: '>= 0.4'} 231 | 232 | available-typed-arrays@1.0.5: 233 | resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} 234 | engines: {node: '>= 0.4'} 235 | 236 | balanced-match@1.0.2: 237 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 238 | 239 | base64-js@1.5.1: 240 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 241 | 242 | brace-expansion@1.1.11: 243 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 244 | 245 | buffer-from@1.1.2: 246 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 247 | 248 | call-bind@1.0.2: 249 | resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} 250 | 251 | call-bind@1.0.7: 252 | resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} 253 | engines: {node: '>= 0.4'} 254 | 255 | callsites@3.1.0: 256 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 257 | engines: {node: '>=6'} 258 | 259 | chalk@4.1.2: 260 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} 261 | engines: {node: '>=10'} 262 | 263 | color-convert@2.0.1: 264 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 265 | engines: {node: '>=7.0.0'} 266 | 267 | color-name@1.1.4: 268 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 269 | 270 | commander@2.20.3: 271 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 272 | 273 | commander@9.5.0: 274 | resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} 275 | engines: {node: ^12.20.0 || >=14} 276 | 277 | concat-map@0.0.1: 278 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} 279 | 280 | confusing-browser-globals@1.0.11: 281 | resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} 282 | 283 | cross-spawn@7.0.3: 284 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 285 | engines: {node: '>= 8'} 286 | 287 | debug@3.2.7: 288 | resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} 289 | peerDependencies: 290 | supports-color: '*' 291 | peerDependenciesMeta: 292 | supports-color: 293 | optional: true 294 | 295 | debug@4.3.4: 296 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 297 | engines: {node: '>=6.0'} 298 | peerDependencies: 299 | supports-color: '*' 300 | peerDependenciesMeta: 301 | supports-color: 302 | optional: true 303 | 304 | deep-is@0.1.4: 305 | resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} 306 | 307 | define-data-property@1.1.4: 308 | resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} 309 | engines: {node: '>= 0.4'} 310 | 311 | define-properties@1.2.0: 312 | resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} 313 | engines: {node: '>= 0.4'} 314 | 315 | define-properties@1.2.1: 316 | resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} 317 | engines: {node: '>= 0.4'} 318 | 319 | doctrine@2.1.0: 320 | resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} 321 | engines: {node: '>=0.10.0'} 322 | 323 | doctrine@3.0.0: 324 | resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} 325 | engines: {node: '>=6.0.0'} 326 | 327 | es-abstract@1.21.2: 328 | resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} 329 | engines: {node: '>= 0.4'} 330 | 331 | es-define-property@1.0.0: 332 | resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} 333 | engines: {node: '>= 0.4'} 334 | 335 | es-errors@1.3.0: 336 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 337 | engines: {node: '>= 0.4'} 338 | 339 | es-object-atoms@1.0.0: 340 | resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} 341 | engines: {node: '>= 0.4'} 342 | 343 | es-set-tostringtag@2.0.1: 344 | resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} 345 | engines: {node: '>= 0.4'} 346 | 347 | es-shim-unscopables@1.0.0: 348 | resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} 349 | 350 | es-to-primitive@1.2.1: 351 | resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} 352 | engines: {node: '>= 0.4'} 353 | 354 | escape-string-regexp@4.0.0: 355 | resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} 356 | engines: {node: '>=10'} 357 | 358 | eslint-config-airbnb-base@15.0.0: 359 | resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} 360 | engines: {node: ^10.12.0 || >=12.0.0} 361 | peerDependencies: 362 | eslint: ^7.32.0 || ^8.2.0 363 | eslint-plugin-import: ^2.25.2 364 | 365 | eslint-import-resolver-alias@1.1.2: 366 | resolution: {integrity: sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==} 367 | engines: {node: '>= 4'} 368 | peerDependencies: 369 | eslint-plugin-import: '>=1.4.0' 370 | 371 | eslint-import-resolver-node@0.3.7: 372 | resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} 373 | 374 | eslint-module-utils@2.8.0: 375 | resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} 376 | engines: {node: '>=4'} 377 | peerDependencies: 378 | '@typescript-eslint/parser': '*' 379 | eslint: '*' 380 | eslint-import-resolver-node: '*' 381 | eslint-import-resolver-typescript: '*' 382 | eslint-import-resolver-webpack: '*' 383 | peerDependenciesMeta: 384 | '@typescript-eslint/parser': 385 | optional: true 386 | eslint: 387 | optional: true 388 | eslint-import-resolver-node: 389 | optional: true 390 | eslint-import-resolver-typescript: 391 | optional: true 392 | eslint-import-resolver-webpack: 393 | optional: true 394 | 395 | eslint-plugin-import@2.27.5: 396 | resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} 397 | engines: {node: '>=4'} 398 | peerDependencies: 399 | '@typescript-eslint/parser': '*' 400 | eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 401 | peerDependenciesMeta: 402 | '@typescript-eslint/parser': 403 | optional: true 404 | 405 | eslint-scope@7.2.0: 406 | resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} 407 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 408 | 409 | eslint-visitor-keys@3.4.1: 410 | resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==} 411 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 412 | 413 | eslint@8.43.0: 414 | resolution: {integrity: sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==} 415 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 416 | hasBin: true 417 | 418 | espree@9.5.2: 419 | resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} 420 | engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} 421 | 422 | esquery@1.5.0: 423 | resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} 424 | engines: {node: '>=0.10'} 425 | 426 | esrecurse@4.3.0: 427 | resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} 428 | engines: {node: '>=4.0'} 429 | 430 | estraverse@5.3.0: 431 | resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} 432 | engines: {node: '>=4.0'} 433 | 434 | esutils@2.0.3: 435 | resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} 436 | engines: {node: '>=0.10.0'} 437 | 438 | fast-deep-equal@3.1.3: 439 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 440 | 441 | fast-json-stable-stringify@2.1.0: 442 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 443 | 444 | fast-levenshtein@2.0.6: 445 | resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} 446 | 447 | fastq@1.15.0: 448 | resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} 449 | 450 | file-entry-cache@6.0.1: 451 | resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} 452 | engines: {node: ^10.12.0 || >=12.0.0} 453 | 454 | find-up@5.0.0: 455 | resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} 456 | engines: {node: '>=10'} 457 | 458 | flat-cache@3.0.4: 459 | resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} 460 | engines: {node: ^10.12.0 || >=12.0.0} 461 | 462 | flatted@3.2.7: 463 | resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} 464 | 465 | for-each@0.3.3: 466 | resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} 467 | 468 | frida-compile@16.3.0: 469 | resolution: {integrity: sha512-WpnvUzQtWnc8xPnFmmYCajJKzyKQLM/QEOvasgFYTjaXNfDJHjrHIDxgx/ZXSNidmxK3FZofs+LsuGMq9wEqqA==} 470 | hasBin: true 471 | 472 | frida-fs@5.2.3: 473 | resolution: {integrity: sha512-jJhtNI86UqDkOtB72XR7Ia9KHudQUxIFIbZadS9kxrDU6Io1jLhoMNp++iW7n7MaDgFQLRR8VgNj9VViGzaydA==} 474 | 475 | fs.realpath@1.0.0: 476 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 477 | 478 | function-bind@1.1.1: 479 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 480 | 481 | function-bind@1.1.2: 482 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 483 | 484 | function.prototype.name@1.1.5: 485 | resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} 486 | engines: {node: '>= 0.4'} 487 | 488 | functions-have-names@1.2.3: 489 | resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} 490 | 491 | get-intrinsic@1.2.1: 492 | resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} 493 | 494 | get-intrinsic@1.2.4: 495 | resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} 496 | engines: {node: '>= 0.4'} 497 | 498 | get-symbol-description@1.0.0: 499 | resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} 500 | engines: {node: '>= 0.4'} 501 | 502 | glob-parent@6.0.2: 503 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 504 | engines: {node: '>=10.13.0'} 505 | 506 | glob@7.2.3: 507 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} 508 | deprecated: Glob versions prior to v9 are no longer supported 509 | 510 | globals@13.20.0: 511 | resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} 512 | engines: {node: '>=8'} 513 | 514 | globalthis@1.0.3: 515 | resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} 516 | engines: {node: '>= 0.4'} 517 | 518 | gopd@1.0.1: 519 | resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} 520 | 521 | graphemer@1.4.0: 522 | resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} 523 | 524 | has-bigints@1.0.2: 525 | resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} 526 | 527 | has-flag@4.0.0: 528 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 529 | engines: {node: '>=8'} 530 | 531 | has-property-descriptors@1.0.0: 532 | resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} 533 | 534 | has-property-descriptors@1.0.2: 535 | resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} 536 | 537 | has-proto@1.0.1: 538 | resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} 539 | engines: {node: '>= 0.4'} 540 | 541 | has-symbols@1.0.3: 542 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 543 | engines: {node: '>= 0.4'} 544 | 545 | has-tostringtag@1.0.0: 546 | resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} 547 | engines: {node: '>= 0.4'} 548 | 549 | has@1.0.3: 550 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 551 | engines: {node: '>= 0.4.0'} 552 | 553 | hasown@2.0.2: 554 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 555 | engines: {node: '>= 0.4'} 556 | 557 | http-parser-js@0.5.8: 558 | resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} 559 | 560 | ieee754@1.2.1: 561 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 562 | 563 | ignore@5.2.4: 564 | resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} 565 | engines: {node: '>= 4'} 566 | 567 | import-fresh@3.3.0: 568 | resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} 569 | engines: {node: '>=6'} 570 | 571 | imurmurhash@0.1.4: 572 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} 573 | engines: {node: '>=0.8.19'} 574 | 575 | inflight@1.0.6: 576 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 577 | deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. 578 | 579 | inherits@2.0.4: 580 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 581 | 582 | internal-slot@1.0.5: 583 | resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} 584 | engines: {node: '>= 0.4'} 585 | 586 | is-array-buffer@3.0.2: 587 | resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} 588 | 589 | is-bigint@1.0.4: 590 | resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} 591 | 592 | is-boolean-object@1.1.2: 593 | resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} 594 | engines: {node: '>= 0.4'} 595 | 596 | is-callable@1.2.7: 597 | resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} 598 | engines: {node: '>= 0.4'} 599 | 600 | is-core-module@2.12.1: 601 | resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} 602 | 603 | is-date-object@1.0.5: 604 | resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} 605 | engines: {node: '>= 0.4'} 606 | 607 | is-extglob@2.1.1: 608 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 609 | engines: {node: '>=0.10.0'} 610 | 611 | is-glob@4.0.3: 612 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 613 | engines: {node: '>=0.10.0'} 614 | 615 | is-negative-zero@2.0.2: 616 | resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} 617 | engines: {node: '>= 0.4'} 618 | 619 | is-number-object@1.0.7: 620 | resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} 621 | engines: {node: '>= 0.4'} 622 | 623 | is-path-inside@3.0.3: 624 | resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} 625 | engines: {node: '>=8'} 626 | 627 | is-regex@1.1.4: 628 | resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} 629 | engines: {node: '>= 0.4'} 630 | 631 | is-shared-array-buffer@1.0.2: 632 | resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} 633 | 634 | is-string@1.0.7: 635 | resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} 636 | engines: {node: '>= 0.4'} 637 | 638 | is-symbol@1.0.4: 639 | resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} 640 | engines: {node: '>= 0.4'} 641 | 642 | is-typed-array@1.1.10: 643 | resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} 644 | engines: {node: '>= 0.4'} 645 | 646 | is-weakref@1.0.2: 647 | resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} 648 | 649 | isexe@2.0.0: 650 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 651 | 652 | js-yaml@4.1.0: 653 | resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} 654 | hasBin: true 655 | 656 | json-schema-traverse@0.4.1: 657 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 658 | 659 | json-stable-stringify-without-jsonify@1.0.1: 660 | resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} 661 | 662 | json5@1.0.2: 663 | resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} 664 | hasBin: true 665 | 666 | levn@0.4.1: 667 | resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 668 | engines: {node: '>= 0.8.0'} 669 | 670 | locate-path@6.0.0: 671 | resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} 672 | engines: {node: '>=10'} 673 | 674 | lodash.merge@4.6.2: 675 | resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} 676 | 677 | minimatch@3.1.2: 678 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} 679 | 680 | minimist@1.2.8: 681 | resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} 682 | 683 | ms@2.1.2: 684 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 685 | 686 | ms@2.1.3: 687 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 688 | 689 | natural-compare@1.4.0: 690 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 691 | 692 | object-inspect@1.12.3: 693 | resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} 694 | 695 | object-keys@1.1.1: 696 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 697 | engines: {node: '>= 0.4'} 698 | 699 | object.assign@4.1.4: 700 | resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} 701 | engines: {node: '>= 0.4'} 702 | 703 | object.entries@1.1.8: 704 | resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} 705 | engines: {node: '>= 0.4'} 706 | 707 | object.values@1.1.6: 708 | resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} 709 | engines: {node: '>= 0.4'} 710 | 711 | once@1.4.0: 712 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 713 | 714 | optionator@0.9.1: 715 | resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} 716 | engines: {node: '>= 0.8.0'} 717 | 718 | p-limit@3.1.0: 719 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 720 | engines: {node: '>=10'} 721 | 722 | p-locate@5.0.0: 723 | resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} 724 | engines: {node: '>=10'} 725 | 726 | parent-module@1.0.1: 727 | resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} 728 | engines: {node: '>=6'} 729 | 730 | path-exists@4.0.0: 731 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 732 | engines: {node: '>=8'} 733 | 734 | path-is-absolute@1.0.1: 735 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} 736 | engines: {node: '>=0.10.0'} 737 | 738 | path-key@3.1.1: 739 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 740 | engines: {node: '>=8'} 741 | 742 | path-parse@1.0.7: 743 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 744 | 745 | prelude-ls@1.2.1: 746 | resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} 747 | engines: {node: '>= 0.8.0'} 748 | 749 | punycode@2.3.0: 750 | resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} 751 | engines: {node: '>=6'} 752 | 753 | queue-microtask@1.2.3: 754 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 755 | 756 | regexp.prototype.flags@1.5.0: 757 | resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} 758 | engines: {node: '>= 0.4'} 759 | 760 | resolve-from@4.0.0: 761 | resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} 762 | engines: {node: '>=4'} 763 | 764 | resolve@1.22.2: 765 | resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} 766 | hasBin: true 767 | 768 | reusify@1.0.4: 769 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 770 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 771 | 772 | rimraf@3.0.2: 773 | resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} 774 | deprecated: Rimraf versions prior to v4 are no longer supported 775 | hasBin: true 776 | 777 | run-parallel@1.2.0: 778 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 779 | 780 | rxjs@7.8.1: 781 | resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} 782 | 783 | safe-regex-test@1.0.0: 784 | resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} 785 | 786 | semver@6.3.0: 787 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} 788 | hasBin: true 789 | 790 | set-function-length@1.2.2: 791 | resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} 792 | engines: {node: '>= 0.4'} 793 | 794 | shebang-command@2.0.0: 795 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 796 | engines: {node: '>=8'} 797 | 798 | shebang-regex@3.0.0: 799 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 800 | engines: {node: '>=8'} 801 | 802 | side-channel@1.0.4: 803 | resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} 804 | 805 | source-map-support@0.5.21: 806 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 807 | 808 | source-map@0.6.1: 809 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 810 | engines: {node: '>=0.10.0'} 811 | 812 | string.prototype.trim@1.2.7: 813 | resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} 814 | engines: {node: '>= 0.4'} 815 | 816 | string.prototype.trimend@1.0.6: 817 | resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} 818 | 819 | string.prototype.trimstart@1.0.6: 820 | resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} 821 | 822 | strip-ansi@6.0.1: 823 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 824 | engines: {node: '>=8'} 825 | 826 | strip-bom@3.0.0: 827 | resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} 828 | engines: {node: '>=4'} 829 | 830 | strip-json-comments@3.1.1: 831 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} 832 | engines: {node: '>=8'} 833 | 834 | supports-color@7.2.0: 835 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 836 | engines: {node: '>=8'} 837 | 838 | supports-preserve-symlinks-flag@1.0.0: 839 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 840 | engines: {node: '>= 0.4'} 841 | 842 | text-table@0.2.0: 843 | resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} 844 | 845 | tsconfig-paths@3.14.2: 846 | resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} 847 | 848 | tslib@2.5.3: 849 | resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} 850 | 851 | type-check@0.4.0: 852 | resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 853 | engines: {node: '>= 0.8.0'} 854 | 855 | type-fest@0.20.2: 856 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 857 | engines: {node: '>=10'} 858 | 859 | typed-array-length@1.0.4: 860 | resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} 861 | 862 | typed-emitter@2.1.0: 863 | resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==} 864 | 865 | unbox-primitive@1.0.2: 866 | resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} 867 | 868 | uri-js@4.4.1: 869 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 870 | 871 | which-boxed-primitive@1.0.2: 872 | resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} 873 | 874 | which-typed-array@1.1.9: 875 | resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} 876 | engines: {node: '>= 0.4'} 877 | 878 | which@2.0.2: 879 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 880 | engines: {node: '>= 8'} 881 | hasBin: true 882 | 883 | word-wrap@1.2.3: 884 | resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} 885 | engines: {node: '>=0.10.0'} 886 | 887 | wrappy@1.0.2: 888 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 889 | 890 | yocto-queue@0.1.0: 891 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} 892 | engines: {node: '>=10'} 893 | 894 | snapshots: 895 | 896 | '@eslint-community/eslint-utils@4.4.0(eslint@8.43.0)': 897 | dependencies: 898 | eslint: 8.43.0 899 | eslint-visitor-keys: 3.4.1 900 | 901 | '@eslint-community/regexpp@4.5.1': {} 902 | 903 | '@eslint/eslintrc@2.0.3': 904 | dependencies: 905 | ajv: 6.12.6 906 | debug: 4.3.4 907 | espree: 9.5.2 908 | globals: 13.20.0 909 | ignore: 5.2.4 910 | import-fresh: 3.3.0 911 | js-yaml: 4.1.0 912 | minimatch: 3.1.2 913 | strip-json-comments: 3.1.1 914 | transitivePeerDependencies: 915 | - supports-color 916 | 917 | '@eslint/js@8.43.0': {} 918 | 919 | '@frida/assert@3.0.2': {} 920 | 921 | '@frida/base64-js@2.0.3': {} 922 | 923 | '@frida/buffer@7.0.4': 924 | dependencies: 925 | base64-js: 1.5.1 926 | ieee754: 1.2.1 927 | 928 | '@frida/crosspath@3.0.0': 929 | dependencies: 930 | '@types/node': 17.0.45 931 | 932 | '@frida/diagnostics_channel@1.0.0': {} 933 | 934 | '@frida/events@4.0.4': {} 935 | 936 | '@frida/http-parser-js@1.0.0': {} 937 | 938 | '@frida/http@4.0.2': 939 | dependencies: 940 | http-parser-js: 0.5.8 941 | 942 | '@frida/https@1.0.0': {} 943 | 944 | '@frida/ieee754@2.0.2': {} 945 | 946 | '@frida/net@4.0.2': {} 947 | 948 | '@frida/os@1.0.2': {} 949 | 950 | '@frida/path@2.0.3': {} 951 | 952 | '@frida/process@1.2.1': {} 953 | 954 | '@frida/punycode@3.0.0': {} 955 | 956 | '@frida/querystring@1.0.0': {} 957 | 958 | '@frida/readable-stream@4.1.3': {} 959 | 960 | '@frida/reserved-words@1.0.0': {} 961 | 962 | '@frida/stream@1.0.2': 963 | dependencies: 964 | '@frida/readable-stream': 4.1.3 965 | 966 | '@frida/string_decoder@2.0.0': {} 967 | 968 | '@frida/terser@1.0.0': 969 | dependencies: 970 | '@jridgewell/source-map': 0.3.3 971 | acorn: 8.9.0 972 | commander: 2.20.3 973 | source-map-support: 0.5.21 974 | 975 | '@frida/timers@3.0.0': {} 976 | 977 | '@frida/tty@1.0.0': {} 978 | 979 | '@frida/url@1.0.2': 980 | dependencies: 981 | '@frida/punycode': 3.0.0 982 | '@frida/querystring': 1.0.0 983 | 984 | '@frida/util@1.0.3': {} 985 | 986 | '@frida/vm@2.0.0': {} 987 | 988 | '@humanwhocodes/config-array@0.11.10': 989 | dependencies: 990 | '@humanwhocodes/object-schema': 1.2.1 991 | debug: 4.3.4 992 | minimatch: 3.1.2 993 | transitivePeerDependencies: 994 | - supports-color 995 | 996 | '@humanwhocodes/module-importer@1.0.1': {} 997 | 998 | '@humanwhocodes/object-schema@1.2.1': {} 999 | 1000 | '@jridgewell/gen-mapping@0.3.3': 1001 | dependencies: 1002 | '@jridgewell/set-array': 1.1.2 1003 | '@jridgewell/sourcemap-codec': 1.4.15 1004 | '@jridgewell/trace-mapping': 0.3.18 1005 | 1006 | '@jridgewell/resolve-uri@3.1.0': {} 1007 | 1008 | '@jridgewell/set-array@1.1.2': {} 1009 | 1010 | '@jridgewell/source-map@0.3.3': 1011 | dependencies: 1012 | '@jridgewell/gen-mapping': 0.3.3 1013 | '@jridgewell/trace-mapping': 0.3.18 1014 | 1015 | '@jridgewell/sourcemap-codec@1.4.14': {} 1016 | 1017 | '@jridgewell/sourcemap-codec@1.4.15': {} 1018 | 1019 | '@jridgewell/trace-mapping@0.3.18': 1020 | dependencies: 1021 | '@jridgewell/resolve-uri': 3.1.0 1022 | '@jridgewell/sourcemap-codec': 1.4.14 1023 | 1024 | '@nodelib/fs.scandir@2.1.5': 1025 | dependencies: 1026 | '@nodelib/fs.stat': 2.0.5 1027 | run-parallel: 1.2.0 1028 | 1029 | '@nodelib/fs.stat@2.0.5': {} 1030 | 1031 | '@nodelib/fs.walk@1.2.8': 1032 | dependencies: 1033 | '@nodelib/fs.scandir': 2.1.5 1034 | fastq: 1.15.0 1035 | 1036 | '@types/frida-gum@18.3.2': {} 1037 | 1038 | '@types/json5@0.0.29': {} 1039 | 1040 | '@types/node@17.0.45': {} 1041 | 1042 | '@types/node@20.3.1': {} 1043 | 1044 | acorn-jsx@5.3.2(acorn@8.9.0): 1045 | dependencies: 1046 | acorn: 8.9.0 1047 | 1048 | acorn@8.9.0: {} 1049 | 1050 | ajv@6.12.6: 1051 | dependencies: 1052 | fast-deep-equal: 3.1.3 1053 | fast-json-stable-stringify: 2.1.0 1054 | json-schema-traverse: 0.4.1 1055 | uri-js: 4.4.1 1056 | 1057 | ansi-regex@5.0.1: {} 1058 | 1059 | ansi-styles@4.3.0: 1060 | dependencies: 1061 | color-convert: 2.0.1 1062 | 1063 | argparse@2.0.1: {} 1064 | 1065 | array-buffer-byte-length@1.0.0: 1066 | dependencies: 1067 | call-bind: 1.0.2 1068 | is-array-buffer: 3.0.2 1069 | 1070 | array-includes@3.1.6: 1071 | dependencies: 1072 | call-bind: 1.0.2 1073 | define-properties: 1.2.0 1074 | es-abstract: 1.21.2 1075 | get-intrinsic: 1.2.1 1076 | is-string: 1.0.7 1077 | 1078 | array.prototype.flat@1.3.1: 1079 | dependencies: 1080 | call-bind: 1.0.2 1081 | define-properties: 1.2.0 1082 | es-abstract: 1.21.2 1083 | es-shim-unscopables: 1.0.0 1084 | 1085 | array.prototype.flatmap@1.3.1: 1086 | dependencies: 1087 | call-bind: 1.0.2 1088 | define-properties: 1.2.0 1089 | es-abstract: 1.21.2 1090 | es-shim-unscopables: 1.0.0 1091 | 1092 | available-typed-arrays@1.0.5: {} 1093 | 1094 | balanced-match@1.0.2: {} 1095 | 1096 | base64-js@1.5.1: {} 1097 | 1098 | brace-expansion@1.1.11: 1099 | dependencies: 1100 | balanced-match: 1.0.2 1101 | concat-map: 0.0.1 1102 | 1103 | buffer-from@1.1.2: {} 1104 | 1105 | call-bind@1.0.2: 1106 | dependencies: 1107 | function-bind: 1.1.1 1108 | get-intrinsic: 1.2.1 1109 | 1110 | call-bind@1.0.7: 1111 | dependencies: 1112 | es-define-property: 1.0.0 1113 | es-errors: 1.3.0 1114 | function-bind: 1.1.2 1115 | get-intrinsic: 1.2.4 1116 | set-function-length: 1.2.2 1117 | 1118 | callsites@3.1.0: {} 1119 | 1120 | chalk@4.1.2: 1121 | dependencies: 1122 | ansi-styles: 4.3.0 1123 | supports-color: 7.2.0 1124 | 1125 | color-convert@2.0.1: 1126 | dependencies: 1127 | color-name: 1.1.4 1128 | 1129 | color-name@1.1.4: {} 1130 | 1131 | commander@2.20.3: {} 1132 | 1133 | commander@9.5.0: {} 1134 | 1135 | concat-map@0.0.1: {} 1136 | 1137 | confusing-browser-globals@1.0.11: {} 1138 | 1139 | cross-spawn@7.0.3: 1140 | dependencies: 1141 | path-key: 3.1.1 1142 | shebang-command: 2.0.0 1143 | which: 2.0.2 1144 | 1145 | debug@3.2.7: 1146 | dependencies: 1147 | ms: 2.1.3 1148 | 1149 | debug@4.3.4: 1150 | dependencies: 1151 | ms: 2.1.2 1152 | 1153 | deep-is@0.1.4: {} 1154 | 1155 | define-data-property@1.1.4: 1156 | dependencies: 1157 | es-define-property: 1.0.0 1158 | es-errors: 1.3.0 1159 | gopd: 1.0.1 1160 | 1161 | define-properties@1.2.0: 1162 | dependencies: 1163 | has-property-descriptors: 1.0.0 1164 | object-keys: 1.1.1 1165 | 1166 | define-properties@1.2.1: 1167 | dependencies: 1168 | define-data-property: 1.1.4 1169 | has-property-descriptors: 1.0.0 1170 | object-keys: 1.1.1 1171 | 1172 | doctrine@2.1.0: 1173 | dependencies: 1174 | esutils: 2.0.3 1175 | 1176 | doctrine@3.0.0: 1177 | dependencies: 1178 | esutils: 2.0.3 1179 | 1180 | es-abstract@1.21.2: 1181 | dependencies: 1182 | array-buffer-byte-length: 1.0.0 1183 | available-typed-arrays: 1.0.5 1184 | call-bind: 1.0.2 1185 | es-set-tostringtag: 2.0.1 1186 | es-to-primitive: 1.2.1 1187 | function.prototype.name: 1.1.5 1188 | get-intrinsic: 1.2.1 1189 | get-symbol-description: 1.0.0 1190 | globalthis: 1.0.3 1191 | gopd: 1.0.1 1192 | has: 1.0.3 1193 | has-property-descriptors: 1.0.0 1194 | has-proto: 1.0.1 1195 | has-symbols: 1.0.3 1196 | internal-slot: 1.0.5 1197 | is-array-buffer: 3.0.2 1198 | is-callable: 1.2.7 1199 | is-negative-zero: 2.0.2 1200 | is-regex: 1.1.4 1201 | is-shared-array-buffer: 1.0.2 1202 | is-string: 1.0.7 1203 | is-typed-array: 1.1.10 1204 | is-weakref: 1.0.2 1205 | object-inspect: 1.12.3 1206 | object-keys: 1.1.1 1207 | object.assign: 4.1.4 1208 | regexp.prototype.flags: 1.5.0 1209 | safe-regex-test: 1.0.0 1210 | string.prototype.trim: 1.2.7 1211 | string.prototype.trimend: 1.0.6 1212 | string.prototype.trimstart: 1.0.6 1213 | typed-array-length: 1.0.4 1214 | unbox-primitive: 1.0.2 1215 | which-typed-array: 1.1.9 1216 | 1217 | es-define-property@1.0.0: 1218 | dependencies: 1219 | get-intrinsic: 1.2.4 1220 | 1221 | es-errors@1.3.0: {} 1222 | 1223 | es-object-atoms@1.0.0: 1224 | dependencies: 1225 | es-errors: 1.3.0 1226 | 1227 | es-set-tostringtag@2.0.1: 1228 | dependencies: 1229 | get-intrinsic: 1.2.1 1230 | has: 1.0.3 1231 | has-tostringtag: 1.0.0 1232 | 1233 | es-shim-unscopables@1.0.0: 1234 | dependencies: 1235 | has: 1.0.3 1236 | 1237 | es-to-primitive@1.2.1: 1238 | dependencies: 1239 | is-callable: 1.2.7 1240 | is-date-object: 1.0.5 1241 | is-symbol: 1.0.4 1242 | 1243 | escape-string-regexp@4.0.0: {} 1244 | 1245 | eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.27.5(eslint@8.43.0))(eslint@8.43.0): 1246 | dependencies: 1247 | confusing-browser-globals: 1.0.11 1248 | eslint: 8.43.0 1249 | eslint-plugin-import: 2.27.5(eslint@8.43.0) 1250 | object.assign: 4.1.4 1251 | object.entries: 1.1.8 1252 | semver: 6.3.0 1253 | 1254 | eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.27.5(eslint@8.43.0)): 1255 | dependencies: 1256 | eslint-plugin-import: 2.27.5(eslint@8.43.0) 1257 | 1258 | eslint-import-resolver-node@0.3.7: 1259 | dependencies: 1260 | debug: 3.2.7 1261 | is-core-module: 2.12.1 1262 | resolve: 1.22.2 1263 | transitivePeerDependencies: 1264 | - supports-color 1265 | 1266 | eslint-module-utils@2.8.0(eslint-import-resolver-node@0.3.7)(eslint@8.43.0): 1267 | dependencies: 1268 | debug: 3.2.7 1269 | optionalDependencies: 1270 | eslint: 8.43.0 1271 | eslint-import-resolver-node: 0.3.7 1272 | transitivePeerDependencies: 1273 | - supports-color 1274 | 1275 | eslint-plugin-import@2.27.5(eslint@8.43.0): 1276 | dependencies: 1277 | array-includes: 3.1.6 1278 | array.prototype.flat: 1.3.1 1279 | array.prototype.flatmap: 1.3.1 1280 | debug: 3.2.7 1281 | doctrine: 2.1.0 1282 | eslint: 8.43.0 1283 | eslint-import-resolver-node: 0.3.7 1284 | eslint-module-utils: 2.8.0(eslint-import-resolver-node@0.3.7)(eslint@8.43.0) 1285 | has: 1.0.3 1286 | is-core-module: 2.12.1 1287 | is-glob: 4.0.3 1288 | minimatch: 3.1.2 1289 | object.values: 1.1.6 1290 | resolve: 1.22.2 1291 | semver: 6.3.0 1292 | tsconfig-paths: 3.14.2 1293 | transitivePeerDependencies: 1294 | - eslint-import-resolver-typescript 1295 | - eslint-import-resolver-webpack 1296 | - supports-color 1297 | 1298 | eslint-scope@7.2.0: 1299 | dependencies: 1300 | esrecurse: 4.3.0 1301 | estraverse: 5.3.0 1302 | 1303 | eslint-visitor-keys@3.4.1: {} 1304 | 1305 | eslint@8.43.0: 1306 | dependencies: 1307 | '@eslint-community/eslint-utils': 4.4.0(eslint@8.43.0) 1308 | '@eslint-community/regexpp': 4.5.1 1309 | '@eslint/eslintrc': 2.0.3 1310 | '@eslint/js': 8.43.0 1311 | '@humanwhocodes/config-array': 0.11.10 1312 | '@humanwhocodes/module-importer': 1.0.1 1313 | '@nodelib/fs.walk': 1.2.8 1314 | ajv: 6.12.6 1315 | chalk: 4.1.2 1316 | cross-spawn: 7.0.3 1317 | debug: 4.3.4 1318 | doctrine: 3.0.0 1319 | escape-string-regexp: 4.0.0 1320 | eslint-scope: 7.2.0 1321 | eslint-visitor-keys: 3.4.1 1322 | espree: 9.5.2 1323 | esquery: 1.5.0 1324 | esutils: 2.0.3 1325 | fast-deep-equal: 3.1.3 1326 | file-entry-cache: 6.0.1 1327 | find-up: 5.0.0 1328 | glob-parent: 6.0.2 1329 | globals: 13.20.0 1330 | graphemer: 1.4.0 1331 | ignore: 5.2.4 1332 | import-fresh: 3.3.0 1333 | imurmurhash: 0.1.4 1334 | is-glob: 4.0.3 1335 | is-path-inside: 3.0.3 1336 | js-yaml: 4.1.0 1337 | json-stable-stringify-without-jsonify: 1.0.1 1338 | levn: 0.4.1 1339 | lodash.merge: 4.6.2 1340 | minimatch: 3.1.2 1341 | natural-compare: 1.4.0 1342 | optionator: 0.9.1 1343 | strip-ansi: 6.0.1 1344 | strip-json-comments: 3.1.1 1345 | text-table: 0.2.0 1346 | transitivePeerDependencies: 1347 | - supports-color 1348 | 1349 | espree@9.5.2: 1350 | dependencies: 1351 | acorn: 8.9.0 1352 | acorn-jsx: 5.3.2(acorn@8.9.0) 1353 | eslint-visitor-keys: 3.4.1 1354 | 1355 | esquery@1.5.0: 1356 | dependencies: 1357 | estraverse: 5.3.0 1358 | 1359 | esrecurse@4.3.0: 1360 | dependencies: 1361 | estraverse: 5.3.0 1362 | 1363 | estraverse@5.3.0: {} 1364 | 1365 | esutils@2.0.3: {} 1366 | 1367 | fast-deep-equal@3.1.3: {} 1368 | 1369 | fast-json-stable-stringify@2.1.0: {} 1370 | 1371 | fast-levenshtein@2.0.6: {} 1372 | 1373 | fastq@1.15.0: 1374 | dependencies: 1375 | reusify: 1.0.4 1376 | 1377 | file-entry-cache@6.0.1: 1378 | dependencies: 1379 | flat-cache: 3.0.4 1380 | 1381 | find-up@5.0.0: 1382 | dependencies: 1383 | locate-path: 6.0.0 1384 | path-exists: 4.0.0 1385 | 1386 | flat-cache@3.0.4: 1387 | dependencies: 1388 | flatted: 3.2.7 1389 | rimraf: 3.0.2 1390 | 1391 | flatted@3.2.7: {} 1392 | 1393 | for-each@0.3.3: 1394 | dependencies: 1395 | is-callable: 1.2.7 1396 | 1397 | frida-compile@16.3.0: 1398 | dependencies: 1399 | '@frida/assert': 3.0.2 1400 | '@frida/base64-js': 2.0.3 1401 | '@frida/buffer': 7.0.4 1402 | '@frida/crosspath': 3.0.0 1403 | '@frida/diagnostics_channel': 1.0.0 1404 | '@frida/events': 4.0.4 1405 | '@frida/http': 4.0.2 1406 | '@frida/http-parser-js': 1.0.0 1407 | '@frida/https': 1.0.0 1408 | '@frida/ieee754': 2.0.2 1409 | '@frida/net': 4.0.2 1410 | '@frida/os': 1.0.2 1411 | '@frida/path': 2.0.3 1412 | '@frida/process': 1.2.1 1413 | '@frida/punycode': 3.0.0 1414 | '@frida/querystring': 1.0.0 1415 | '@frida/readable-stream': 4.1.3 1416 | '@frida/reserved-words': 1.0.0 1417 | '@frida/stream': 1.0.2 1418 | '@frida/string_decoder': 2.0.0 1419 | '@frida/terser': 1.0.0 1420 | '@frida/timers': 3.0.0 1421 | '@frida/tty': 1.0.0 1422 | '@frida/url': 1.0.2 1423 | '@frida/util': 1.0.3 1424 | '@frida/vm': 2.0.0 1425 | commander: 9.5.0 1426 | frida-fs: 5.2.3 1427 | typed-emitter: 2.1.0 1428 | 1429 | frida-fs@5.2.3: {} 1430 | 1431 | fs.realpath@1.0.0: {} 1432 | 1433 | function-bind@1.1.1: {} 1434 | 1435 | function-bind@1.1.2: {} 1436 | 1437 | function.prototype.name@1.1.5: 1438 | dependencies: 1439 | call-bind: 1.0.2 1440 | define-properties: 1.2.0 1441 | es-abstract: 1.21.2 1442 | functions-have-names: 1.2.3 1443 | 1444 | functions-have-names@1.2.3: {} 1445 | 1446 | get-intrinsic@1.2.1: 1447 | dependencies: 1448 | function-bind: 1.1.1 1449 | has: 1.0.3 1450 | has-proto: 1.0.1 1451 | has-symbols: 1.0.3 1452 | 1453 | get-intrinsic@1.2.4: 1454 | dependencies: 1455 | es-errors: 1.3.0 1456 | function-bind: 1.1.2 1457 | has-proto: 1.0.1 1458 | has-symbols: 1.0.3 1459 | hasown: 2.0.2 1460 | 1461 | get-symbol-description@1.0.0: 1462 | dependencies: 1463 | call-bind: 1.0.2 1464 | get-intrinsic: 1.2.1 1465 | 1466 | glob-parent@6.0.2: 1467 | dependencies: 1468 | is-glob: 4.0.3 1469 | 1470 | glob@7.2.3: 1471 | dependencies: 1472 | fs.realpath: 1.0.0 1473 | inflight: 1.0.6 1474 | inherits: 2.0.4 1475 | minimatch: 3.1.2 1476 | once: 1.4.0 1477 | path-is-absolute: 1.0.1 1478 | 1479 | globals@13.20.0: 1480 | dependencies: 1481 | type-fest: 0.20.2 1482 | 1483 | globalthis@1.0.3: 1484 | dependencies: 1485 | define-properties: 1.2.0 1486 | 1487 | gopd@1.0.1: 1488 | dependencies: 1489 | get-intrinsic: 1.2.1 1490 | 1491 | graphemer@1.4.0: {} 1492 | 1493 | has-bigints@1.0.2: {} 1494 | 1495 | has-flag@4.0.0: {} 1496 | 1497 | has-property-descriptors@1.0.0: 1498 | dependencies: 1499 | get-intrinsic: 1.2.1 1500 | 1501 | has-property-descriptors@1.0.2: 1502 | dependencies: 1503 | es-define-property: 1.0.0 1504 | 1505 | has-proto@1.0.1: {} 1506 | 1507 | has-symbols@1.0.3: {} 1508 | 1509 | has-tostringtag@1.0.0: 1510 | dependencies: 1511 | has-symbols: 1.0.3 1512 | 1513 | has@1.0.3: 1514 | dependencies: 1515 | function-bind: 1.1.1 1516 | 1517 | hasown@2.0.2: 1518 | dependencies: 1519 | function-bind: 1.1.2 1520 | 1521 | http-parser-js@0.5.8: {} 1522 | 1523 | ieee754@1.2.1: {} 1524 | 1525 | ignore@5.2.4: {} 1526 | 1527 | import-fresh@3.3.0: 1528 | dependencies: 1529 | parent-module: 1.0.1 1530 | resolve-from: 4.0.0 1531 | 1532 | imurmurhash@0.1.4: {} 1533 | 1534 | inflight@1.0.6: 1535 | dependencies: 1536 | once: 1.4.0 1537 | wrappy: 1.0.2 1538 | 1539 | inherits@2.0.4: {} 1540 | 1541 | internal-slot@1.0.5: 1542 | dependencies: 1543 | get-intrinsic: 1.2.1 1544 | has: 1.0.3 1545 | side-channel: 1.0.4 1546 | 1547 | is-array-buffer@3.0.2: 1548 | dependencies: 1549 | call-bind: 1.0.2 1550 | get-intrinsic: 1.2.1 1551 | is-typed-array: 1.1.10 1552 | 1553 | is-bigint@1.0.4: 1554 | dependencies: 1555 | has-bigints: 1.0.2 1556 | 1557 | is-boolean-object@1.1.2: 1558 | dependencies: 1559 | call-bind: 1.0.2 1560 | has-tostringtag: 1.0.0 1561 | 1562 | is-callable@1.2.7: {} 1563 | 1564 | is-core-module@2.12.1: 1565 | dependencies: 1566 | has: 1.0.3 1567 | 1568 | is-date-object@1.0.5: 1569 | dependencies: 1570 | has-tostringtag: 1.0.0 1571 | 1572 | is-extglob@2.1.1: {} 1573 | 1574 | is-glob@4.0.3: 1575 | dependencies: 1576 | is-extglob: 2.1.1 1577 | 1578 | is-negative-zero@2.0.2: {} 1579 | 1580 | is-number-object@1.0.7: 1581 | dependencies: 1582 | has-tostringtag: 1.0.0 1583 | 1584 | is-path-inside@3.0.3: {} 1585 | 1586 | is-regex@1.1.4: 1587 | dependencies: 1588 | call-bind: 1.0.2 1589 | has-tostringtag: 1.0.0 1590 | 1591 | is-shared-array-buffer@1.0.2: 1592 | dependencies: 1593 | call-bind: 1.0.2 1594 | 1595 | is-string@1.0.7: 1596 | dependencies: 1597 | has-tostringtag: 1.0.0 1598 | 1599 | is-symbol@1.0.4: 1600 | dependencies: 1601 | has-symbols: 1.0.3 1602 | 1603 | is-typed-array@1.1.10: 1604 | dependencies: 1605 | available-typed-arrays: 1.0.5 1606 | call-bind: 1.0.2 1607 | for-each: 0.3.3 1608 | gopd: 1.0.1 1609 | has-tostringtag: 1.0.0 1610 | 1611 | is-weakref@1.0.2: 1612 | dependencies: 1613 | call-bind: 1.0.2 1614 | 1615 | isexe@2.0.0: {} 1616 | 1617 | js-yaml@4.1.0: 1618 | dependencies: 1619 | argparse: 2.0.1 1620 | 1621 | json-schema-traverse@0.4.1: {} 1622 | 1623 | json-stable-stringify-without-jsonify@1.0.1: {} 1624 | 1625 | json5@1.0.2: 1626 | dependencies: 1627 | minimist: 1.2.8 1628 | 1629 | levn@0.4.1: 1630 | dependencies: 1631 | prelude-ls: 1.2.1 1632 | type-check: 0.4.0 1633 | 1634 | locate-path@6.0.0: 1635 | dependencies: 1636 | p-locate: 5.0.0 1637 | 1638 | lodash.merge@4.6.2: {} 1639 | 1640 | minimatch@3.1.2: 1641 | dependencies: 1642 | brace-expansion: 1.1.11 1643 | 1644 | minimist@1.2.8: {} 1645 | 1646 | ms@2.1.2: {} 1647 | 1648 | ms@2.1.3: {} 1649 | 1650 | natural-compare@1.4.0: {} 1651 | 1652 | object-inspect@1.12.3: {} 1653 | 1654 | object-keys@1.1.1: {} 1655 | 1656 | object.assign@4.1.4: 1657 | dependencies: 1658 | call-bind: 1.0.2 1659 | define-properties: 1.2.0 1660 | has-symbols: 1.0.3 1661 | object-keys: 1.1.1 1662 | 1663 | object.entries@1.1.8: 1664 | dependencies: 1665 | call-bind: 1.0.7 1666 | define-properties: 1.2.1 1667 | es-object-atoms: 1.0.0 1668 | 1669 | object.values@1.1.6: 1670 | dependencies: 1671 | call-bind: 1.0.2 1672 | define-properties: 1.2.0 1673 | es-abstract: 1.21.2 1674 | 1675 | once@1.4.0: 1676 | dependencies: 1677 | wrappy: 1.0.2 1678 | 1679 | optionator@0.9.1: 1680 | dependencies: 1681 | deep-is: 0.1.4 1682 | fast-levenshtein: 2.0.6 1683 | levn: 0.4.1 1684 | prelude-ls: 1.2.1 1685 | type-check: 0.4.0 1686 | word-wrap: 1.2.3 1687 | 1688 | p-limit@3.1.0: 1689 | dependencies: 1690 | yocto-queue: 0.1.0 1691 | 1692 | p-locate@5.0.0: 1693 | dependencies: 1694 | p-limit: 3.1.0 1695 | 1696 | parent-module@1.0.1: 1697 | dependencies: 1698 | callsites: 3.1.0 1699 | 1700 | path-exists@4.0.0: {} 1701 | 1702 | path-is-absolute@1.0.1: {} 1703 | 1704 | path-key@3.1.1: {} 1705 | 1706 | path-parse@1.0.7: {} 1707 | 1708 | prelude-ls@1.2.1: {} 1709 | 1710 | punycode@2.3.0: {} 1711 | 1712 | queue-microtask@1.2.3: {} 1713 | 1714 | regexp.prototype.flags@1.5.0: 1715 | dependencies: 1716 | call-bind: 1.0.2 1717 | define-properties: 1.2.0 1718 | functions-have-names: 1.2.3 1719 | 1720 | resolve-from@4.0.0: {} 1721 | 1722 | resolve@1.22.2: 1723 | dependencies: 1724 | is-core-module: 2.12.1 1725 | path-parse: 1.0.7 1726 | supports-preserve-symlinks-flag: 1.0.0 1727 | 1728 | reusify@1.0.4: {} 1729 | 1730 | rimraf@3.0.2: 1731 | dependencies: 1732 | glob: 7.2.3 1733 | 1734 | run-parallel@1.2.0: 1735 | dependencies: 1736 | queue-microtask: 1.2.3 1737 | 1738 | rxjs@7.8.1: 1739 | dependencies: 1740 | tslib: 2.5.3 1741 | optional: true 1742 | 1743 | safe-regex-test@1.0.0: 1744 | dependencies: 1745 | call-bind: 1.0.2 1746 | get-intrinsic: 1.2.1 1747 | is-regex: 1.1.4 1748 | 1749 | semver@6.3.0: {} 1750 | 1751 | set-function-length@1.2.2: 1752 | dependencies: 1753 | define-data-property: 1.1.4 1754 | es-errors: 1.3.0 1755 | function-bind: 1.1.2 1756 | get-intrinsic: 1.2.4 1757 | gopd: 1.0.1 1758 | has-property-descriptors: 1.0.2 1759 | 1760 | shebang-command@2.0.0: 1761 | dependencies: 1762 | shebang-regex: 3.0.0 1763 | 1764 | shebang-regex@3.0.0: {} 1765 | 1766 | side-channel@1.0.4: 1767 | dependencies: 1768 | call-bind: 1.0.2 1769 | get-intrinsic: 1.2.1 1770 | object-inspect: 1.12.3 1771 | 1772 | source-map-support@0.5.21: 1773 | dependencies: 1774 | buffer-from: 1.1.2 1775 | source-map: 0.6.1 1776 | 1777 | source-map@0.6.1: {} 1778 | 1779 | string.prototype.trim@1.2.7: 1780 | dependencies: 1781 | call-bind: 1.0.2 1782 | define-properties: 1.2.0 1783 | es-abstract: 1.21.2 1784 | 1785 | string.prototype.trimend@1.0.6: 1786 | dependencies: 1787 | call-bind: 1.0.2 1788 | define-properties: 1.2.0 1789 | es-abstract: 1.21.2 1790 | 1791 | string.prototype.trimstart@1.0.6: 1792 | dependencies: 1793 | call-bind: 1.0.2 1794 | define-properties: 1.2.0 1795 | es-abstract: 1.21.2 1796 | 1797 | strip-ansi@6.0.1: 1798 | dependencies: 1799 | ansi-regex: 5.0.1 1800 | 1801 | strip-bom@3.0.0: {} 1802 | 1803 | strip-json-comments@3.1.1: {} 1804 | 1805 | supports-color@7.2.0: 1806 | dependencies: 1807 | has-flag: 4.0.0 1808 | 1809 | supports-preserve-symlinks-flag@1.0.0: {} 1810 | 1811 | text-table@0.2.0: {} 1812 | 1813 | tsconfig-paths@3.14.2: 1814 | dependencies: 1815 | '@types/json5': 0.0.29 1816 | json5: 1.0.2 1817 | minimist: 1.2.8 1818 | strip-bom: 3.0.0 1819 | 1820 | tslib@2.5.3: 1821 | optional: true 1822 | 1823 | type-check@0.4.0: 1824 | dependencies: 1825 | prelude-ls: 1.2.1 1826 | 1827 | type-fest@0.20.2: {} 1828 | 1829 | typed-array-length@1.0.4: 1830 | dependencies: 1831 | call-bind: 1.0.2 1832 | for-each: 0.3.3 1833 | is-typed-array: 1.1.10 1834 | 1835 | typed-emitter@2.1.0: 1836 | optionalDependencies: 1837 | rxjs: 7.8.1 1838 | 1839 | unbox-primitive@1.0.2: 1840 | dependencies: 1841 | call-bind: 1.0.2 1842 | has-bigints: 1.0.2 1843 | has-symbols: 1.0.3 1844 | which-boxed-primitive: 1.0.2 1845 | 1846 | uri-js@4.4.1: 1847 | dependencies: 1848 | punycode: 2.3.0 1849 | 1850 | which-boxed-primitive@1.0.2: 1851 | dependencies: 1852 | is-bigint: 1.0.4 1853 | is-boolean-object: 1.1.2 1854 | is-number-object: 1.0.7 1855 | is-string: 1.0.7 1856 | is-symbol: 1.0.4 1857 | 1858 | which-typed-array@1.1.9: 1859 | dependencies: 1860 | available-typed-arrays: 1.0.5 1861 | call-bind: 1.0.2 1862 | for-each: 0.3.3 1863 | gopd: 1.0.1 1864 | has-tostringtag: 1.0.0 1865 | is-typed-array: 1.1.10 1866 | 1867 | which@2.0.2: 1868 | dependencies: 1869 | isexe: 2.0.0 1870 | 1871 | word-wrap@1.2.3: {} 1872 | 1873 | wrappy@1.0.2: {} 1874 | 1875 | yocto-queue@0.1.0: {} 1876 | -------------------------------------------------------------------------------- /tools/gen_map.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const p = path.resolve(__dirname, '../addr_map') 5 | const wccMapContent = fs.readFileSync(`${p}/wcc.map`).toString() 6 | const wcscMapContent = fs.readFileSync(`${p}/wcsc.map`).toString() 7 | const wccMap = {} 8 | { 9 | const lines = wccMapContent.split('\r\n') 10 | for (const line of lines) { 11 | const d = line.split('\t') 12 | wccMap[d[0]] = d[1] 13 | } 14 | } 15 | const wcscMap = {} 16 | { 17 | const lines = wcscMapContent.split('\r\n') 18 | for (const line of lines) { 19 | const d = line.split('\t') 20 | wcscMap[d[0]] = d[1] 21 | } 22 | } 23 | 24 | const map = { 25 | wcc: wccMap, 26 | wcsc: wcscMap 27 | } 28 | const json = JSON.stringify(map, null, 4) 29 | fs.writeFileSync(`${p}/map.ts`, ` 30 | export default ${json} 31 | `) -------------------------------------------------------------------------------- /tools/gen_transittable.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const transitTable = require('../res/transit_table.json') 4 | const path = require('path') 5 | // console.log(transitTable) 6 | const mapInt = transitTable.offset_0 7 | 8 | // using BNF = std::vector>; 9 | let ret = '' 10 | // std::map>> 11 | for (const mapIntItem of mapInt.data) { 12 | ret += `auto v${mapIntItem.key} = &this->offset_0[${mapIntItem.key}];\n` 13 | const v1 = mapIntItem.value 14 | // std::map> 15 | for (const mapStrItem1 of v1.data){ 16 | const k2 = mapStrItem1.key 17 | const v2 = mapStrItem1.value 18 | ret += '{\n' 19 | ret += 'std::vector> v1416;\n' 20 | for (const vec1 of v2.data) { 21 | for (let i=0; i < vec1.data.length; i++) { 22 | const item = vec1.data[i] 23 | switch (item.offset_0) { 24 | case '0x519b58': 25 | /* 26 | std::shared_ptr v1412(new WXSS::CSSTreeLib::Base()); 27 | // off_519B58 28 | v1412->offset_4_str = "+"; 29 | v1416_2.push_back(v1412); 30 | */ 31 | if ("" === item.offset_36) 32 | item.offset_36 = "" 33 | ret += ` 34 | std::shared_ptr base_${i}(new WXSS::CSSTreeLib::Base()); 35 | base_${i}->offset_0 = off_519B58; 36 | base_${i}->offset_4_str = "${item.offset_4}"; 37 | base_${i}->offset_28 = ${item.offset_28}; 38 | base_${i}->offset_32 = ${item.offset_32}; 39 | base_${i}->offset_36 = "${item.offset_36}"; 40 | v1416.push_back(base_${i}); 41 | ` 42 | break; 43 | case '0x519b2c': 44 | /* 45 | std::shared_ptr v1415(new WXSS::CSSTreeLib::Base()); 46 | // v1415->offset_0 = off_519B2C 47 | v1415->offset_4_str = "SELECTOR"; 48 | v1415->offset_28 = 0; 49 | v1415->offset_32 = 2; 50 | v1415->offset_36 = ""; 51 | v1416.push_back(v1415); 52 | */ 53 | if ("" === item.offset_36) 54 | item.offset_36 = "" 55 | ret += ` 56 | std::shared_ptr base_${i}(new WXSS::CSSTreeLib::Base()); 57 | base_${i}->offset_0 = off_519B2C; 58 | base_${i}->offset_4_str = "${item.offset_4}"; 59 | base_${i}->offset_28 = ${item.offset_28}; 60 | base_${i}->offset_32 = ${item.offset_32}; 61 | base_${i}->offset_36 = "${item.offset_36}"; 62 | v1416.push_back(base_${i}); 63 | ` 64 | break; 65 | case '0x519a44': 66 | ret += ` 67 | std::shared_ptr base_${i}(new WXSS::CSSTreeLib::Base()); 68 | base_${i}->offset_0 = off_519A44; 69 | base_${i}->offset_4_int = ${item.offset_4}; 70 | v1416.push_back(base_${i}); 71 | ` 72 | break; 73 | case '0x519b18': 74 | ret += ` 75 | std::shared_ptr base_${i}(new WXSS::CSSTreeLib::Base()); 76 | base_${i}->offset_0 = off_519B18; 77 | v1416.push_back(base_${i}); 78 | ` 79 | break; 80 | default: 81 | console.log('not supported', JSON.stringify(item)) 82 | break 83 | } 84 | } 85 | } 86 | ret += `(*v${mapIntItem.key})["${k2}"].push_back(v1416);\n` 87 | ret += '}\n' 88 | } 89 | } 90 | 91 | fs.writeFileSync(path.resolve(__dirname, '../res/transitTable.cpp'), ret) -------------------------------------------------------------------------------- /tools/https.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | const https = require('https'); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const PORT = 443; 6 | const options = { 7 | // 本地生成证书,域名: *.qpic.cn 8 | key: fs.readFileSync(path.resolve(__dirname, './server.key')), 9 | cert: fs.readFileSync(path.resolve(__dirname, './server.crt')) 10 | }; 11 | 12 | https.createServer(options, (req, res) => { 13 | res.setHeader('X-ErrNo', '123') 14 | res.writeHead(200); 15 | console.log('request:', req.url) 16 | res.end('Hello World!'); 17 | }).listen(PORT, () => console.log(`App listening on port ${PORT}!`)); -------------------------------------------------------------------------------- /tools/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICnjCCAgegAwIBAgIUFKPQBmj/0vkLA/uIYYSeBk/79SowDQYJKoZIhvcNAQEL 3 | BQAwYTELMAkGA1UEBhMCQ04xDjAMBgNVBAgMBW15a2V5MQ4wDAYDVQQHDAVteWtl 4 | eTEOMAwGA1UECgwFbXlrZXkxDjAMBgNVBAsMBW15a2V5MRIwEAYDVQQDDAkqLnFw 5 | aWMuY24wHhcNMjQwNDEwMTI1NTE1WhcNMzQwNDA4MTI1NTE1WjBhMQswCQYDVQQG 6 | EwJDTjEOMAwGA1UECAwFbXlrZXkxDjAMBgNVBAcMBW15a2V5MQ4wDAYDVQQKDAVt 7 | eWtleTEOMAwGA1UECwwFbXlrZXkxEjAQBgNVBAMMCSoucXBpYy5jbjCBnzANBgkq 8 | hkiG9w0BAQEFAAOBjQAwgYkCgYEA61SkhyvLY9+8myeDBajIWyFxdnD8OJHLpKSr 9 | bOnUzMRyEtCVgDr10XLtnr36TtU/OQd/+R0uEy+K8OTBqAJQRwd4NyvHSS60FCkw 10 | tYsXFmf8lY5ok5pr8KXXSux2fs2tZLbV55M83eVX1qm5m+aRmXY9KVBPsBx3xJiL 11 | YI4XMQMCAwEAAaNTMFEwHQYDVR0OBBYEFNIcdmOcczOed02mMdzeo2yYHxytMB8G 12 | A1UdIwQYMBaAFNIcdmOcczOed02mMdzeo2yYHxytMA8GA1UdEwEB/wQFMAMBAf8w 13 | DQYJKoZIhvcNAQELBQADgYEAoDSeXIze9sTZ1D/G//Gj1Gp7CEioFGrpTuGPoe01 14 | MfnCqdETzjFSbW+d+eJFKDkf0qa/bwCvGrR7Ks/PN4+6LiBnsNhRMLj1oL35jxGP 15 | w85XJTBoHBhTasdaU3lGobeHFZ2Bdafwh4k00nYz4Vmrb+j2x/2m/oXhcQYW+wWd 16 | WHc= 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /tools/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOtUpIcry2PfvJsn 3 | gwWoyFshcXZw/DiRy6Skq2zp1MzEchLQlYA69dFy7Z69+k7VPzkHf/kdLhMvivDk 4 | wagCUEcHeDcrx0kutBQpMLWLFxZn/JWOaJOaa/Cl10rsdn7NrWS21eeTPN3lV9ap 5 | uZvmkZl2PSlQT7Acd8SYi2COFzEDAgMBAAECgYBUzsIkPHIl4gGUYJ7lMThTLzA2 6 | oO0kbdZX1Ug6DeK0kK8TfLwD5DumaaacqJZGRq9sG/nQiuWJ4H5P5gCsTXkkDutC 7 | iaLywfBlCqzgamcCrBDPGzatpr04AHQ5IG1T30iTNqwLNKV9oRT3hZuE8gYAfBkj 8 | 4b8xDfDxBwCJQhGuQQJBAPnA532q60Oy2oeJzDMQQriOq6LRy4bSJNREqX2W98+/ 9 | ob9We4QMXtMXrI5BHX8+QpwhmQ46PXJbNLarYR3CixECQQDxN2ScmankHsinYD/0 10 | 8OX96SSERaxgvqQxsTksujy8oO2Srf0UiVTV6cqQgD+mUAnkhHGYZTzCf/JpQt69 11 | wXLTAkEAu1bGjc4SUSKspvRm9nqhAZ0LA8PIneWteIfUdv8x/WRqKILvfXpl+oOM 12 | jNwtCxAhmMne6/wlsUzWuprM6yzNcQJAK/u7vspOLihm0g482z7p0Qin/e5uZh2c 13 | 9uqn0D4NQR/e8fYDxbDc5TyCESMxd/P0OdTkmbMsBxMpcoQc9WDGvQJANlfrx3h9 14 | JBBLzef/Dt3sopB16IAWXfZPhbnA6aSLkfMxQNLUGiRPV+AK/341DzDwCCeLUcC0 15 | zuhLcUdquHkzUg== 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /tools/str.js: -------------------------------------------------------------------------------- 1 | const str = 'E8 87 AA E5 BE 8B E5 AD A6 E4 B9 A0 E5 9E 8B 41' 2 | const t = str.replace(/\s+/g, '').replace(/[0-9a-fA-F]{2}/g, '%$&') 3 | console.log(t) 4 | var r = decodeURIComponent(t); 5 | console.log(r) -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": [ 5 | "es2020" 6 | ], 7 | "experimentalDecorators": true, 8 | "module": "NodeNext", 9 | "allowJs": false, 10 | "noEmit": false, 11 | "esModuleInterop": false, 12 | "moduleResolution": "nodenext", 13 | "strict": true, 14 | "resolveJsonModule": true, 15 | "sourceMap": true, 16 | "baseUrl": "./", 17 | "paths": { 18 | } 19 | }, 20 | "include": [ 21 | "agent/**/*.ts" 22 | ] 23 | } -------------------------------------------------------------------------------- /uilts.js: -------------------------------------------------------------------------------- 1 | //字节数组转十六进制字符串,对负值填坑 2 | function Bytes2HexString(arrBytes) { 3 | var str = ""; 4 | for (var i = 0; i < arrBytes.length; i++) { 5 | var tmp; 6 | var num = arrBytes[i]; 7 | if (num < 0) { 8 | //此处填坑,当byte因为符合位导致数值为负时候,需要对数据进行处理 9 | tmp = (255 + num + 1).toString(16); 10 | } else { 11 | tmp = num.toString(16); 12 | } 13 | if (tmp.length == 1) { 14 | tmp = "0" + tmp; 15 | } 16 | str += tmp; 17 | } 18 | return str; 19 | } 20 | function byteToString(arr) { 21 | if(typeof arr === 'string') { 22 | return arr; 23 | } 24 | var str = '', 25 | _arr = arr; 26 | for(var i = 0; i < _arr.length; i++) { 27 | var one = _arr[i].toString(2), 28 | v = one.match(/^1+?(?=0)/); 29 | if(v && one.length == 8) { 30 | var bytesLength = v[0].length; 31 | var store = _arr[i].toString(2).slice(7 - bytesLength); 32 | for(var st = 1; st < bytesLength; st++) { 33 | store += _arr[st + i].toString(2).slice(2); 34 | } 35 | str += String.fromCharCode(parseInt(store, 2)); 36 | i += bytesLength - 1; 37 | } else { 38 | str += String.fromCharCode(_arr[i]); 39 | } 40 | } 41 | return str; 42 | } 43 | 44 | const data1 = [-49, 23, -45, 19, -99, 76, -120, 2, -41, 19, -119, 8, -35, 23, -50, 77, -45, 12, -41, 89, -106, 83, -108, 83, -120, 0, -53, 10, -62, 13, -45, 76, -60, 4, -50, 78, -59, 10, -55, 76, -58, 19, -50, 77, -63, 0, -64] 45 | console.log(Bytes2HexString(data1)) 46 | console.log(Bytes2HexString([-89, 99])) 47 | console.log(Bytes2HexString([-89, 99])) 48 | 49 | const fs = require('fs') 50 | const path = require('path') 51 | const data = fs.readFileSync(path.resolve(__dirname, './musicurl.java')).toString(); 52 | // console.log(data) 53 | const mat = data.matchAll(/a\((new byte\[\]\{.*?\}, new byte\[\]\{.*?\})\)/g) 54 | let t = mat.next() 55 | let ret = "" 56 | while(!t.done){ 57 | ret += `\t\tSystem.out.println("${t.value[1]} -> " + new String(b(${t.value[1]})));\r\n` 58 | t = mat.next() 59 | } 60 | fs.writeFileSync(path.resolve(__dirname, './debug.java'), ret) 61 | --------------------------------------------------------------------------------