SandboXP

Форк
0
/
elf.js 
222 строки · 5.8 Кб
1
"use strict";
2

3
// A minimal elf parser for loading 32 bit, x86, little endian, executable elf files
4

5
const ELF_MAGIC = 0x464C457F;
6

7
let types = DataView.prototype;
8
let U8 = { size: 1, get: types.getUint8, set: types.setUint8, };
9
let U16 = { size: 2, get: types.getUint16, set: types.setUint16, };
10
let U32 = { size: 4, get: types.getUint32, set: types.setUint32, };
11
let pad = function(size)
12
{
13
    return {
14
        size,
15
        get: offset => -1,
16
    };
17
};
18

19
let Header = create_struct([
20
    { magic: U32, },
21

22
    { class: U8, },
23
    { data: U8, },
24
    { version0: U8, },
25
    { osabi: U8, },
26

27
    { abiversion: U8, },
28
    { pad0: pad(7) },
29

30
    { type: U16, },
31
    { machine: U16, },
32

33
    { version1: U32, },
34
    { entry: U32, },
35
    { phoff: U32, },
36
    { shoff: U32, },
37
    { flags: U32, },
38

39
    { ehsize: U16, },
40
    { phentsize: U16, },
41
    { phnum: U16, },
42
    { shentsize: U16, },
43
    { shnum: U16, },
44
    { shstrndx: U16, },
45
]);
46
console.assert(Header.reduce((a, entry) => a + entry.size, 0) === 52);
47

48
let ProgramHeader = create_struct([
49
    { type: U32, },
50
    { offset: U32, },
51
    { vaddr: U32, },
52
    { paddr: U32, },
53
    { filesz: U32, },
54
    { memsz: U32, },
55
    { flags: U32, },
56
    { align: U32, },
57
]);
58
console.assert(ProgramHeader.reduce((a, entry) => a + entry.size, 0) === 32);
59

60
let SectionHeader = create_struct([
61
    { name: U32, },
62
    { type: U32, },
63
    { flags: U32, },
64
    { addr: U32, },
65
    { offset: U32, },
66
    { size: U32, },
67
    { link: U32, },
68
    { info: U32, },
69
    { addralign: U32, },
70
    { entsize: U32, },
71
]);
72
console.assert(SectionHeader.reduce((a, entry) => a + entry.size, 0) === 40);
73

74

75
// From [{ name: type }, ...] to [{ name, type, size, get, set }, ...]
76
function create_struct(struct)
77
{
78
    return struct.map(function(entry)
79
    {
80
        let keys = Object.keys(entry);
81
        console.assert(keys.length === 1);
82
        let name = keys[0];
83
        let type = entry[name];
84

85
        console.assert(type.size > 0);
86

87
        return {
88
            name,
89
            type,
90
            size: type.size,
91
            get: type.get,
92
            set: type.set,
93
        };
94
    });
95
}
96

97
/** @param {ArrayBuffer} buffer */
98
function read_elf(buffer)
99
{
100
    let view = new DataView(buffer);
101

102
    let [header, offset] = read_struct(view, Header);
103
    console.assert(offset === 52);
104

105
    if(DEBUG)
106
    {
107
        for(let key of Object.keys(header))
108
        {
109
            dbg_log(key + ": 0x" + header[key].toString(16));
110
        }
111
        dbg_log(header);
112
    }
113

114
    console.assert(header.magic === ELF_MAGIC, "Bad magic");
115
    console.assert(header.class === 1, "Unimplemented: 64 bit elf");
116
    console.assert(header.data === 1, "Unimplemented: big endian");
117
    console.assert(header.version0 === 1, "Bad version0");
118

119
    // 1, 2, 3, 4 specify whether the object is relocatable, executable,
120
    // shared, or core, respectively.
121
    console.assert(header.type === 2, "Unimplemented type");
122

123
    console.assert(header.version1 === 1, "Bad version1");
124

125
    // these are different in 64 bit
126
    console.assert(header.ehsize === 52, "Bad header size");
127
    console.assert(header.phentsize === 32, "Bad program header size");
128
    console.assert(header.shentsize === 40, "Bad section header size");
129

130
    let [program_headers, ph_offset] = read_structs(
131
        view_slice(view, header.phoff, header.phentsize * header.phnum),
132
        ProgramHeader,
133
        header.phnum);
134

135
    let [sections_headers, sh_offset] = read_structs(
136
        view_slice(view, header.shoff, header.shentsize * header.shnum),
137
        SectionHeader,
138
        header.shnum);
139

140
    if(DEBUG && LOG_LEVEL)
141
    {
142
        console.log("%d program headers:", program_headers.length);
143
        for(let program of program_headers)
144
        {
145
            console.log(
146
                "type=%s offset=%s vaddr=%s paddr=%s " +
147
                "filesz=%s memsz=%s flags=%s align=%s",
148
                program.type.toString(16),
149
                program.offset.toString(16),
150
                program.vaddr.toString(16),
151
                program.paddr.toString(16),
152
                program.filesz.toString(16),
153
                program.memsz.toString(16),
154
                program.flags.toString(16),
155
                program.align.toString(16)
156
            );
157
        }
158

159
        console.log("%d program headers:", sections_headers.length);
160
        for(let section of sections_headers)
161
        {
162
            console.log(
163
                "name=%s type=%s flags=%s addr=%s offset=%s " +
164
                "size=%s link=%s info=%s addralign=%s entsize=%s",
165
                section.name.toString(16),
166
                section.type.toString(16),
167
                section.flags.toString(16),
168
                section.addr.toString(16),
169
                section.offset.toString(16),
170
                section.size.toString(16),
171
                section.link.toString(16),
172
                section.info.toString(16),
173
                section.addralign.toString(16),
174
                section.entsize.toString(16)
175
            );
176
        }
177
    }
178

179
    return {
180
        header,
181
        program_headers,
182
        sections_headers,
183
    };
184
}
185

186
function read_struct(view, Struct)
187
{
188
    let result = {};
189
    let offset = 0;
190
    const LITTLE_ENDIAN = true; // big endian not supported yet
191

192
    for(let entry of Struct)
193
    {
194
        let value = entry.get.call(view, offset, LITTLE_ENDIAN);
195
        console.assert(result[entry.name] === undefined);
196
        result[entry.name] = value;
197
        offset += entry.size;
198
    }
199

200
    return [result, offset];
201
}
202

203
function read_structs(view, Struct, count)
204
{
205
    let result = [];
206
    let offset = 0;
207

208
    for(var i = 0; i < count; i++)
209
    {
210
        let [s, size] = read_struct(view_slice(view, offset), Struct);
211
        result.push(s);
212
        offset += size;
213
    }
214

215
    return [result, offset];
216
}
217

218
/** @param {number=} length */
219
function view_slice(view, offset, length)
220
{
221
    return new DataView(view.buffer, view.byteOffset + offset, length);
222
}
223

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.