@isopodlabs/binary_libs 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitmodules +3 -0
- package/.vscode/launch.json +16 -0
- package/.vscode/settings.json +3 -0
- package/README.md +152 -44
- package/eslint.config.mjs +32 -0
- package/package.json +11 -3
- package/src/CompoundDocument.ts +5 -5
- package/src/arch.ts +16 -13
- package/src/clr.ts +53 -58
- package/src/elf.ts +544 -545
- package/src/mach.ts +172 -121
- package/src/pe.ts +209 -213
- package/transform.ts +369 -0
- package/tsconfig.json +10 -3
- package/tsconfig.tsbuildinfo +1 -0
- package/dist/CompoundDocument.d.ts +0 -129
- package/dist/CompoundDocument.js +0 -301
- package/dist/arch.d.ts +0 -41
- package/dist/arch.js +0 -94
- package/dist/binary.d.ts +0 -397
- package/dist/binary.js +0 -802
- package/dist/binary_helpers.d.ts +0 -69
- package/dist/binary_helpers.js +0 -328
- package/dist/clr.d.ts +0 -63
- package/dist/clr.js +0 -664
- package/dist/elf.d.ts +0 -11
- package/dist/elf.js +0 -791
- package/dist/mach.d.ts +0 -543
- package/dist/mach.js +0 -1034
- package/dist/pe.d.ts +0 -399
- package/dist/pe.js +0 -489
package/.gitmodules
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
|
|
8
|
+
{
|
|
9
|
+
"type": "node-terminal",
|
|
10
|
+
"name": "Run Script: build",
|
|
11
|
+
"request": "launch",
|
|
12
|
+
"command": "npm run build",
|
|
13
|
+
"cwd": "${workspaceFolder}"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
package/README.md
CHANGED
|
@@ -1,60 +1,168 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Binary Libs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package provides readers for various library formats, using the @isopodlabs/binary binary file loading library
|
|
4
4
|
|
|
5
|
-
This package provides a set of utilities for reading and writing binary data in TypeScript. It includes various interfaces, types, and functions to facilitate binary data manipulation.
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## Supported File Types
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
### elf
|
|
9
|
+
ELF
|
|
10
|
+
```typescript
|
|
11
|
+
class ELFFile {
|
|
12
|
+
segments: [string, any][];
|
|
13
|
+
sections: [string, any][];
|
|
14
|
+
symbols?: [string, any][];
|
|
15
|
+
dynamic_symbols?: [string, any][];
|
|
16
|
+
header: any;
|
|
17
|
+
static check(data: Uint8Array): boolean;
|
|
18
|
+
constructor(data: Uint8Array);
|
|
19
|
+
getSymbols(type: binary.Type, data: Uint8Array, names: Uint8Array): [string, any][];
|
|
20
|
+
}
|
|
10
21
|
|
|
11
22
|
```
|
|
12
|
-
npm install my-binary-package
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Usage
|
|
16
|
-
|
|
17
|
-
Here is a basic example of how to use the package:
|
|
18
23
|
|
|
24
|
+
### pe
|
|
25
|
+
Portable Executable
|
|
19
26
|
```typescript
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Write data back to the stream
|
|
35
|
-
const writeStream = new stream(new Uint8Array(1024));
|
|
36
|
-
const myWriteStruct = WriteStruct({
|
|
37
|
-
// Define your structure here
|
|
38
|
-
});
|
|
39
|
-
myWriteStruct.put(writeStream, myData);
|
|
27
|
+
class PE {
|
|
28
|
+
static check(data: Uint8Array): boolean;
|
|
29
|
+
constructor(data: Uint8Array);
|
|
30
|
+
get directories(): {
|
|
31
|
+
[k: string]: any;
|
|
32
|
+
} | undefined;
|
|
33
|
+
FindSectionRVA(rva: number): Section | undefined;
|
|
34
|
+
FindSectionRaw(addr: number): Section | undefined;
|
|
35
|
+
GetDataRVA(rva: number, size?: number): binary.utils.MappedMemory | undefined;
|
|
36
|
+
GetDataRaw(addr: number, size: number): Uint8Array | undefined;
|
|
37
|
+
GetDataDir(dir: { VirtualAddress: number; Size: number; } & {}): binary.utils.MappedMemory | undefined;
|
|
38
|
+
ReadDirectory(name: string): any;
|
|
39
|
+
}
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
### clr
|
|
43
|
+
Common Language Runtime (embedded in pe files)
|
|
44
|
+
```typescript
|
|
45
|
+
class CLR {
|
|
46
|
+
header: any;
|
|
47
|
+
table_info: any;
|
|
48
|
+
heaps: Uint8Array[];
|
|
49
|
+
tables: Record<TABLE, Table>;
|
|
50
|
+
raw?: Uint8Array;
|
|
51
|
+
Resources?: Uint8Array;
|
|
52
|
+
constructor(pe: pe.PE, clr_data: Uint8Array);
|
|
53
|
+
getEntry(t: TABLE, i: number): any;
|
|
54
|
+
getTable(t: TABLE.Module): ({ generation: number; name: string; mvid: string; encid: string; encbaseid: string; } & {})[];
|
|
55
|
+
getTable(t: TABLE.TypeRef): ({ scope: number; name: string; namespce: string; } & {})[];
|
|
56
|
+
getTable(t: TABLE.TypeDef): ({ flags: number; name: string; namespce: string; extends: number; fields: number; methods: number; } & {})[];
|
|
57
|
+
getTable(t: TABLE.Field): ({ flags: number; name: string; signature: Uint8Array; } & {})[];
|
|
58
|
+
getTable(t: TABLE.MethodDef): ({ code: number; implflags: number; flags: number; name: string; signature: Uint8Array; paramlist: number; } & {})[];
|
|
59
|
+
getTable(t: TABLE.Param): ({ flags: number; sequence: number; name: string; } & {})[];
|
|
60
|
+
getTable(t: TABLE.InterfaceImpl): ({ clss: number; interfce: number; } & {})[];
|
|
61
|
+
getTable(t: TABLE.MemberRef): ({ clss: number; name: string; signature: Uint8Array; } & {})[];
|
|
62
|
+
getTable(t: TABLE.Constant): ({ type: number; parent: number; value: Uint8Array; } & {})[];
|
|
63
|
+
getTable(t: TABLE.CustomAttribute): ({ parent: number; type: number; value: Uint8Array; } & {})[];
|
|
64
|
+
getTable(t: TABLE.FieldMarshal): ({ parent: number; native_type: Uint8Array; } & {})[];
|
|
65
|
+
getTable(t: TABLE.DeclSecurity): ({ action: number; parent: number; permission_set: Uint8Array; } & {})[];
|
|
66
|
+
getTable(t: TABLE.ClassLayout): ({ packing_size: number; class_size: number; parent: number; } & {})[];
|
|
67
|
+
getTable(t: TABLE.FieldLayout): ({ offset: number; field: number; } & {})[];
|
|
68
|
+
getTable(t: TABLE.StandAloneSig): ({ signature: Uint8Array; } & {})[];
|
|
69
|
+
getTable(t: TABLE.EventMap): ({ parent: number; event_list: number; } & {})[];
|
|
70
|
+
getTable(t: TABLE.Event): ({ flags: number; name: string; event_type: number; } & {})[];
|
|
71
|
+
getTable(t: TABLE.PropertyMap): ({ parent: number; property_list: number; } & {})[];
|
|
72
|
+
getTable(t: TABLE.Property): ({ flags: number; name: string; type: Uint8Array; } & {})[];
|
|
73
|
+
getTable(t: TABLE.MethodSemantics): ({ flags: number; method: number; association: number; } & {})[];
|
|
74
|
+
getTable(t: TABLE.MethodImpl): ({ clss: number; method_body: number; method_declaration: number; } & {})[];
|
|
75
|
+
getTable(t: TABLE.ModuleRef): ({ name: string; } & {})[];
|
|
76
|
+
getTable(t: TABLE.TypeSpec): ({ signature: Uint8Array; } & {})[];
|
|
77
|
+
getTable(t: TABLE.ImplMap): ({ flags: number; member_forwarded: number; name: string; scope: number; } & {})[];
|
|
78
|
+
getTable(t: TABLE.FieldRVA): ({ rva: number; field: number; } & {})[];
|
|
79
|
+
getTable(t: TABLE.Assembly): ({ hashalg: number; major: number; minor: number; build: number; rev: number; flags: number; publickey: Uint8Array; name: string; culture: string; } & {})[];
|
|
80
|
+
getTable(t: TABLE.AssemblyProcessor): ({ processor: number; } & {})[];
|
|
81
|
+
getTable(t: TABLE.AssemblyOS): ({ platform: number; minor: number; major: number; } & {})[];
|
|
82
|
+
getTable(t: TABLE.AssemblyRef): ({ major: number; minor: number; build: number; rev: number; flags: number; publickey: Uint8Array; name: string; culture: string; hashvalue: Uint8Array; } & {})[];
|
|
83
|
+
getTable(t: TABLE.AssemblyRefProcessor): ({ processor: number; assembly: number; } & {})[];
|
|
84
|
+
getTable(t: TABLE.AssemblyRefOS): ({ platform: number; major: number; minor: number; assembly: number; } & {})[];
|
|
85
|
+
getTable(t: TABLE.File): ({ flags: number; name: string; hash: Uint8Array; } & {})[];
|
|
86
|
+
getTable(t: TABLE.ExportedType): ({ flags: number; typedef_id: number; name: string; namespce: string; implementation: number; } & {})[];
|
|
87
|
+
getTable(t: TABLE.ManifestResource): ({ data: number; flags: number; name: string; implementation: number; } & {})[];
|
|
88
|
+
getTable(t: TABLE.NestedClass): ({ nested_class: number; enclosing_class: number; } & {})[];
|
|
89
|
+
getTable(t: TABLE.GenericParam): ({ number: number; flags: number; owner: number; name: string; } & {})[];
|
|
90
|
+
getTable(t: TABLE.MethodSpec): ({ method: number; instantiation: Uint8Array; } & {})[];
|
|
91
|
+
getTable(t: TABLE.GenericParamConstraint): ({ owner: number; constraint: number; } & {})[];
|
|
92
|
+
getResources(block: string): Record<string, any> | undefined;
|
|
93
|
+
getResource(block: string, name: string): any;
|
|
94
|
+
allResources(): {} | undefined;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
### mach
|
|
98
|
+
Apple libraries
|
|
99
|
+
```typescript
|
|
100
|
+
declare function segment(bits: 32 | 64): {
|
|
101
|
+
get(s: mach_stream): Promise<{
|
|
102
|
+
data: binary.utils.MappedMemory | undefined;
|
|
103
|
+
segname: string;
|
|
104
|
+
vmaddr: number | bigint;
|
|
105
|
+
vmsize: number | bigint;
|
|
106
|
+
fileoff: number | bigint;
|
|
107
|
+
filesize: number | bigint;
|
|
108
|
+
maxprot: number;
|
|
109
|
+
initprot: number;
|
|
110
|
+
nsects: number;
|
|
111
|
+
flags: Record<string, bigint | boolean> | Record<string, number | boolean>;
|
|
112
|
+
sections: Record<string, any> | undefined;
|
|
113
|
+
} & {}>;
|
|
114
|
+
};
|
|
115
|
+
export declare class MachFile {
|
|
116
|
+
header: any;
|
|
117
|
+
commands: { cmd: CMD; data: any; }[];
|
|
118
|
+
ready: Promise<void>;
|
|
119
|
+
static check(data: Uint8Array): boolean;
|
|
120
|
+
constructor(data: Uint8Array, mem?: binary.utils.memory);
|
|
121
|
+
load(data: Uint8Array, be: boolean, bits: 32 | 64, mem?: binary.utils.memory): Promise<void>;
|
|
122
|
+
getCommand(cmd: number): any;
|
|
123
|
+
getSegment(name: string): Promise<{ data: binary.utils.MappedMemory | undefined; segname: string; vmaddr: number | bigint; vmsize: number | bigint; fileoff: number | bigint; filesize: number | bigint; maxprot: number; initprot: number; nsects: number; flags: Record<string, bigint | boolean> | Record<string, number | boolean>; sections: Record<string, any> | undefined; } & {}> | undefined;
|
|
124
|
+
}
|
|
125
|
+
class FATMachFile {
|
|
126
|
+
archs: ({ cputype: string; cpusubtype: string | number; offset: number; size: number; align: number; contents: MachFile | undefined; } & {})[];
|
|
127
|
+
static check(data: Uint8Array): boolean;
|
|
128
|
+
constructor(data: Uint8Array, mem?: binary.utils.memory);
|
|
129
|
+
load(file: binary.stream_endian, mem?: binary.utils.memory): void;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
53
132
|
|
|
54
|
-
|
|
133
|
+
### arch
|
|
134
|
+
Archive files for static linking
|
|
55
135
|
|
|
56
|
-
|
|
136
|
+
```typescript
|
|
137
|
+
type HEADER = {
|
|
138
|
+
name: string;
|
|
139
|
+
date: number;
|
|
140
|
+
uid: number;
|
|
141
|
+
gid: number;
|
|
142
|
+
mode: number;
|
|
143
|
+
size: number;
|
|
144
|
+
fmag: string;
|
|
145
|
+
contents: any;
|
|
146
|
+
};
|
|
147
|
+
declare class ArchFile {
|
|
148
|
+
members: HEADER[];
|
|
149
|
+
static check(data: Uint8Array): boolean;
|
|
150
|
+
constructor(data: Uint8Array);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
57
153
|
|
|
154
|
+
### CompoundDocument
|
|
155
|
+
Not a library format at all, but useful for loading some related files
|
|
156
|
+
```typescript
|
|
157
|
+
class Reader {
|
|
158
|
+
entries: DirEntry[];
|
|
159
|
+
private entry_chain;
|
|
160
|
+
constructor(sectors: Uint8Array, header: Header);
|
|
161
|
+
find(name: string, i?: number): DirEntry | undefined;
|
|
162
|
+
read(e: DirEntry): Uint8Array;
|
|
163
|
+
write(e: DirEntry, data: Uint8Array): void;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
58
166
|
## License
|
|
59
167
|
|
|
60
168
|
This project is licensed under the MIT License. See the LICENSE file for more details.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import eslint from "@eslint/js";
|
|
3
|
+
import tslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
export default tslint.config(
|
|
6
|
+
eslint.configs.recommended,
|
|
7
|
+
...tslint.configs.recommended,
|
|
8
|
+
...tslint.configs.stylistic,
|
|
9
|
+
{
|
|
10
|
+
rules: {
|
|
11
|
+
"semi": ["error", "always"], // Add this line to enforce semicolon use
|
|
12
|
+
"no-empty": "off",
|
|
13
|
+
//"@typescript-eslint/no-misleading-character-class": "off",
|
|
14
|
+
//"@typescript-eslint/no-this-alias": "off",
|
|
15
|
+
"@typescript-eslint/no-unused-vars": [
|
|
16
|
+
"warn", {
|
|
17
|
+
argsIgnorePattern: "^(_+$|_[^_])",
|
|
18
|
+
varsIgnorePattern: "^(_+$|_[^_])",
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
22
|
+
//"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
23
|
+
//"@typescript-eslint/no-non-null-assertion": "off"
|
|
24
|
+
"@typescript-eslint/no-empty-function": "off",
|
|
25
|
+
"@typescript-eslint/consistent-indexed-object-style": "off",
|
|
26
|
+
"@typescript-eslint/consistent-type-definitions": "off"
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
files: ["src/*.ts"],
|
|
31
|
+
}
|
|
32
|
+
);
|
package/package.json
CHANGED
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc",
|
|
14
|
-
"
|
|
14
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
15
|
+
"test": "echo \"No tests specified\" && exit 0",
|
|
16
|
+
"postinstall": "ts-patch install"
|
|
15
17
|
},
|
|
16
18
|
"keywords": [
|
|
17
19
|
"binary",
|
|
@@ -24,10 +26,16 @@
|
|
|
24
26
|
"license": "MIT",
|
|
25
27
|
"devDependencies": {
|
|
26
28
|
"@types/node": "^22.13.8",
|
|
27
|
-
"typescript": "^
|
|
29
|
+
"@typescript-eslint/eslint-plugin": "^8.26.0",
|
|
30
|
+
"@typescript-eslint/parser": "^8.26.0",
|
|
31
|
+
"eslint": "^9.21.0",
|
|
32
|
+
"ts-node": "^10.9.2",
|
|
33
|
+
"ts-patch": "^3.3.0",
|
|
34
|
+
"typescript": "~5.5.0",
|
|
35
|
+
"typescript-eslint": "^8.26.0"
|
|
28
36
|
},
|
|
29
37
|
"dependencies": {
|
|
30
38
|
"@isopodlabs/binary": "^1.0.3"
|
|
31
39
|
},
|
|
32
|
-
"version": "0.0
|
|
40
|
+
"version": "0.1.0"
|
|
33
41
|
}
|
package/src/CompoundDocument.ts
CHANGED
|
@@ -14,7 +14,7 @@ class FAT {
|
|
|
14
14
|
dirty_fat = new Set<number>();
|
|
15
15
|
dirty_sec = new Set<number>();
|
|
16
16
|
|
|
17
|
-
constructor(size: number, public shift:number, public sectors: Uint8Array) {
|
|
17
|
+
constructor(size: number, public shift: number, public sectors: Uint8Array) {
|
|
18
18
|
this.fat = new Int32Array(size);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -99,7 +99,7 @@ class FAT {
|
|
|
99
99
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
export class Header extends binary.
|
|
102
|
+
export class Header extends binary.Class({
|
|
103
103
|
magic: binary.UINT64_BE,
|
|
104
104
|
id: binary.Buffer(16),
|
|
105
105
|
revision: binary.UINT16_LE,
|
|
@@ -137,7 +137,7 @@ const COLOUR = {
|
|
|
137
137
|
RED: 0, BLACK: 1
|
|
138
138
|
} as const;
|
|
139
139
|
|
|
140
|
-
class DirEntry extends binary.
|
|
140
|
+
class DirEntry extends binary.Class({
|
|
141
141
|
name: binary.StringType(64, 'utf16le'),
|
|
142
142
|
name_size: binary.UINT16_LE,
|
|
143
143
|
type: binary.UINT8,
|
|
@@ -164,7 +164,7 @@ class DirEntry extends binary.ReadWriteStruct({
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
class Master {
|
|
168
168
|
difat: Int32Array;
|
|
169
169
|
fat: FAT;
|
|
170
170
|
mini_fat: FAT;
|
|
@@ -259,7 +259,7 @@ export class Reader extends Master {
|
|
|
259
259
|
this.entries[i] = new DirEntry(i, r2.seek(i * 128));
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
find(name: string, i
|
|
262
|
+
find(name: string, i = 0): DirEntry|undefined {
|
|
263
263
|
const stack: number[] = [];
|
|
264
264
|
let sp = 0;
|
|
265
265
|
|
package/src/arch.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import * as binary from '@isopodlabs/binary';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
name: binary.as(binary.StringType(16), x => {
|
|
3
|
+
const _HEADER = {
|
|
4
|
+
name: binary.as(binary.StringType(16), x => {
|
|
5
|
+
x = x.trim();
|
|
6
|
+
return x.endsWith('/') ? x.slice(0, -1) : x;
|
|
7
|
+
}),
|
|
5
8
|
date: binary.asInt(binary.StringType(12)),
|
|
6
9
|
uid: binary.asInt(binary.StringType(6)),
|
|
7
10
|
gid: binary.asInt(binary.StringType(6)),
|
|
@@ -11,17 +14,18 @@ const AR_MEMBER_HEADER = {
|
|
|
11
14
|
contents: binary.DontRead<any>()
|
|
12
15
|
};
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
export type HEADER = binary.ReadType<typeof _HEADER>;
|
|
18
|
+
|
|
19
|
+
const SYM64 = {
|
|
15
20
|
name: binary.StringType(12),
|
|
16
21
|
offset: binary.asInt(binary.StringType(4))
|
|
17
22
|
};
|
|
18
23
|
|
|
19
24
|
export class ArchFile {
|
|
20
|
-
members:
|
|
25
|
+
members: HEADER[] = [];
|
|
21
26
|
|
|
22
27
|
static check(data: Uint8Array): boolean {
|
|
23
|
-
|
|
24
|
-
return x == '!<arch>\n';
|
|
28
|
+
return binary.utils.decodeText(data.subarray(0, 8), 'utf8') == '!<arch>\n';
|
|
25
29
|
}
|
|
26
30
|
constructor(data: Uint8Array) {
|
|
27
31
|
const s = new binary.stream(data);
|
|
@@ -32,7 +36,7 @@ export class ArchFile {
|
|
|
32
36
|
|
|
33
37
|
let long_names;
|
|
34
38
|
while (s.remaining() > 0) {
|
|
35
|
-
const member = binary.read(s,
|
|
39
|
+
const member = binary.read(s, _HEADER);
|
|
36
40
|
const data = s.read_buffer(member.size);
|
|
37
41
|
s.align(2);
|
|
38
42
|
|
|
@@ -46,8 +50,8 @@ export class ArchFile {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
if (member.name == '') {
|
|
49
|
-
const s2
|
|
50
|
-
const offsets
|
|
53
|
+
const s2 = new binary.stream(data);
|
|
54
|
+
const offsets = binary.ArrayType(binary.INT32_BE, binary.INT32_BE).get(s2);
|
|
51
55
|
member.name = 'Symbols';
|
|
52
56
|
member.contents = offsets.map(offset => [
|
|
53
57
|
binary.NullTerminatedStringType.get(s2),
|
|
@@ -55,9 +59,8 @@ export class ArchFile {
|
|
|
55
59
|
]);
|
|
56
60
|
|
|
57
61
|
} else if (member.name == '/SYM') {
|
|
58
|
-
const s2
|
|
59
|
-
const syms
|
|
60
|
-
|
|
62
|
+
const s2 = new binary.stream(data);
|
|
63
|
+
const syms = binary.ArrayType(binary.INT32_BE, binary.NullTerminatedStringType).get(s2);
|
|
61
64
|
member.contents = syms.map(name => ({
|
|
62
65
|
name,
|
|
63
66
|
offset: binary.INT32_BE.get(s2)
|
|
@@ -65,7 +68,7 @@ export class ArchFile {
|
|
|
65
68
|
|
|
66
69
|
} else if (member.name == '/SYM64') {
|
|
67
70
|
const s2 = new binary.stream(data);
|
|
68
|
-
member.contents = binary.RemainingArrayType(
|
|
71
|
+
member.contents = binary.RemainingArrayType(SYM64).get(s2);
|
|
69
72
|
|
|
70
73
|
} else {
|
|
71
74
|
member.contents = data;
|
package/src/clr.ts
CHANGED
|
@@ -26,7 +26,7 @@ const CLR_HEADER = {
|
|
|
26
26
|
MajorRuntimeVersion: binary.UINT16_LE,
|
|
27
27
|
MinorRuntimeVersion: binary.UINT16_LE,
|
|
28
28
|
MetaData: pe.DATA_DIRECTORY,
|
|
29
|
-
Flags: binary.UINT32_LE,
|
|
29
|
+
Flags: binary.asFlags(binary.UINT32_LE, CLR_FLAGS),
|
|
30
30
|
EntryPoint: binary.UINT32_LE,
|
|
31
31
|
Resources: pe.DATA_DIRECTORY,
|
|
32
32
|
StrongNameSignature: pe.DATA_DIRECTORY,
|
|
@@ -185,16 +185,16 @@ class clr_dummy extends binary.dummy {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
const clr_String = {
|
|
188
|
-
get(s: clr_stream)
|
|
189
|
-
put(
|
|
188
|
+
get(s: clr_stream) { return s.getString(); },
|
|
189
|
+
put(_s: clr_stream, _v : number) {}
|
|
190
190
|
};
|
|
191
191
|
const clr_GUID = {
|
|
192
|
-
get(s: clr_stream)
|
|
193
|
-
put(
|
|
192
|
+
get(s: clr_stream) { return s.getGUID(); },
|
|
193
|
+
put(_s: clr_stream, _v : number) {}
|
|
194
194
|
};
|
|
195
195
|
const clr_Blob = {
|
|
196
|
-
get(s: clr_stream)
|
|
197
|
-
put(
|
|
196
|
+
get(s: clr_stream) { return s.getBlob(); },
|
|
197
|
+
put(_s: clr_stream, _v : number) {}
|
|
198
198
|
};
|
|
199
199
|
const Signature = clr_Blob;
|
|
200
200
|
const CustomAttributeValue = clr_Blob;
|
|
@@ -429,7 +429,7 @@ const ENTRY_GenericParamConstraint = {
|
|
|
429
429
|
constraint: TypeDefOrRef,
|
|
430
430
|
};
|
|
431
431
|
|
|
432
|
-
const TableReaders
|
|
432
|
+
const TableReaders = {
|
|
433
433
|
[TABLE.Module]: ENTRY_Module,
|
|
434
434
|
[TABLE.TypeRef]: ENTRY_TypeRef,
|
|
435
435
|
[TABLE.TypeDef]: ENTRY_TypeDef,
|
|
@@ -476,14 +476,12 @@ const ResourceManagerHeader = {
|
|
|
476
476
|
skip: binary.UINT32_LE,
|
|
477
477
|
};
|
|
478
478
|
|
|
479
|
-
const pascal_string = binary.StringType(binary.UINT8);
|
|
480
|
-
|
|
481
479
|
const ResourceManager = {
|
|
482
|
-
reader:
|
|
483
|
-
set:
|
|
480
|
+
reader: binary.StringType(binary.UINT8),// Class name of IResourceReader to parse this file
|
|
481
|
+
set: binary.StringType(binary.UINT8),// Class name of ResourceSet to parse this file
|
|
484
482
|
version: binary.UINT32_LE,
|
|
485
483
|
num_resources: binary.UINT32_LE,
|
|
486
|
-
types: binary.ArrayType(binary.UINT32_LE,
|
|
484
|
+
types: binary.ArrayType(binary.UINT32_LE, binary.StringType(binary.UINT8)),
|
|
487
485
|
};
|
|
488
486
|
|
|
489
487
|
const ResourceEntry = {
|
|
@@ -497,7 +495,7 @@ export class CLR {
|
|
|
497
495
|
header: any;
|
|
498
496
|
table_info: any;
|
|
499
497
|
heaps: Uint8Array[] = [];
|
|
500
|
-
tables
|
|
498
|
+
tables!: Record<TABLE, Table>;
|
|
501
499
|
raw?: Uint8Array;
|
|
502
500
|
Resources?: Uint8Array;
|
|
503
501
|
/*
|
|
@@ -511,56 +509,50 @@ export class CLR {
|
|
|
511
509
|
}
|
|
512
510
|
*/
|
|
513
511
|
constructor(pe: pe.PE, clr_data: Uint8Array) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
case "#Blob": this.heaps[HEAP.Blob] = mem; break;
|
|
532
|
-
}
|
|
512
|
+
this.header = binary.read(new binary.stream(clr_data), CLR_HEADER);
|
|
513
|
+
const meta_data = pe.GetDataDir(this.header.MetaData);
|
|
514
|
+
const meta_root = meta_data && binary.read(new binary.stream(meta_data.data), METADATA_ROOT);
|
|
515
|
+
|
|
516
|
+
if (meta_root?.Signature != binary.utils.stringCode('BSJB'))
|
|
517
|
+
throw new Error("Invalid CLR");
|
|
518
|
+
|
|
519
|
+
let table_data;
|
|
520
|
+
|
|
521
|
+
for (const h of meta_root!.Streams) {
|
|
522
|
+
const mem = meta_data!.data.subarray(h.Offset, h.Offset + h.Size);
|
|
523
|
+
switch (h.Name) {
|
|
524
|
+
case "#~": table_data = mem; break;
|
|
525
|
+
case "#Strings": this.heaps[HEAP.String] = mem; break;
|
|
526
|
+
case "#US": this.heaps[HEAP.UserString] = mem; break;
|
|
527
|
+
case "#GUID": this.heaps[HEAP.GUID] = mem; break;
|
|
528
|
+
case "#Blob": this.heaps[HEAP.Blob] = mem; break;
|
|
533
529
|
}
|
|
530
|
+
}
|
|
534
531
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
532
|
+
if (table_data) {
|
|
533
|
+
const stream = new binary.stream(table_data);
|
|
534
|
+
this.table_info = binary.read(stream, CLR_TABLES);
|
|
535
|
+
const table_counts: number[] = [];
|
|
539
536
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
537
|
+
//read counts
|
|
538
|
+
for (let b = this.table_info.Valid; b; b = binary.utils.clearLowest(b)) {
|
|
539
|
+
const i = binary.utils.lowestSetIndex(b);
|
|
540
|
+
table_counts[i] = binary.UINT32_LE.get(stream);
|
|
541
|
+
}
|
|
545
542
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
let offset = 0;
|
|
550
|
-
|
|
551
|
-
for (let b = this.table_info.Valid; b; b = binary.utils.clearLowest(b)) {
|
|
552
|
-
const i = binary.utils.lowestSetIndex(b) as TABLE;
|
|
553
|
-
stream1.seek(0);
|
|
554
|
-
binary.read(stream1, TableReaders[i]);
|
|
555
|
-
this.tables[i] = {offset, count: table_counts[i], size: stream1.tell()};
|
|
556
|
-
offset += this.tables[i]!.size * this.tables[i]!.count;
|
|
557
|
-
}
|
|
543
|
+
this.raw = stream.remainder();
|
|
544
|
+
const stream1 = new clr_dummy(this.table_info.HeapSizes, table_counts);
|
|
545
|
+
let offset = 0;
|
|
558
546
|
|
|
559
|
-
|
|
547
|
+
for (let b = this.table_info.Valid; b; b = binary.utils.clearLowest(b)) {
|
|
548
|
+
const i = binary.utils.lowestSetIndex(b) as TABLE;
|
|
549
|
+
stream1.seek(0);
|
|
550
|
+
binary.read(stream1, TableReaders[i]);
|
|
551
|
+
this.tables[i] = {offset, count: table_counts[i], size: stream1.tell()};
|
|
552
|
+
offset += this.tables[i]!.size * this.tables[i]!.count;
|
|
560
553
|
}
|
|
561
554
|
|
|
562
|
-
|
|
563
|
-
console.log(e);
|
|
555
|
+
this.Resources = pe.GetDataDir(this.header.Resources)?.data;
|
|
564
556
|
}
|
|
565
557
|
}
|
|
566
558
|
|
|
@@ -573,6 +565,7 @@ export class CLR {
|
|
|
573
565
|
}
|
|
574
566
|
}
|
|
575
567
|
|
|
568
|
+
getTable<T extends TABLE> (t: T): binary.ReadType<typeof TableReaders[T]>[];
|
|
576
569
|
getTable(t: TABLE) {
|
|
577
570
|
const table = this.tables[t];
|
|
578
571
|
if (table) {
|
|
@@ -639,7 +632,9 @@ function getResources(data: Uint8Array) {
|
|
|
639
632
|
}
|
|
640
633
|
}
|
|
641
634
|
|
|
642
|
-
|
|
635
|
+
// hook into PE reader
|
|
636
|
+
|
|
637
|
+
pe.DIRECTORIES.CLR_DESCRIPTOR.read = (pe: pe.PE, data: binary.MappedMemory) => {
|
|
643
638
|
function fix_names(table: any[]) {
|
|
644
639
|
if ('name' in table[0])
|
|
645
640
|
return Object.fromEntries(table.map(i => [i.name, i]));
|