Тема: JavaScript: дамп ApiSet v6 (расширение WinDbg)
Пригодится всем интересующимся внутренним устройством Windows.
'use strict';
const is_kd = () => host.currentSession.Attributes.Target.IsKernelTarget;
const chunk = ([a1, a2, ...tail]) => tail.length // Windows - это LE система
? [[a1, a2].reverse(), ...chunk(tail)] : [[a1, a2].reverse()];
const read_struct = (arr, adr) => {
return ((fields, values) => { // размерность полей одинакова, поэтому
return fields.reduce((hash, key, index) => { // не используем синтетики
hash[key] = values[index];
return hash;
}, {});
})(arr, host.memory.readMemoryValues(adr, arr.length, 4));
}
const read_string = (adr, len) => {
return String.fromCharCode(...chunk( // разбор символов Unicode
host.memory.readMemoryValues(adr, len, 1)
).map(c => c.join('').padStart(4, '0')));
}
class ApiSetEnrty {
constructor(entry, sealed, points) {
this.Entry = entry;
this.Sealed = sealed;
this.Points = points.join(', ');
}
}
/*
* .scriptload apiset.js
* dx -g @$apiset()
* [...] <- кликабельно в WinDbg
* dx -c 100 -g @$apiset()
* [...]
* dx -c 200 -g @$apiset()
* [...]
* и так далее
*/
function *EnumerateApiSetEntries() {
let peb = is_kd() ? host.createPointerObject(
host.currentProcess.KernelObject.Peb.address, 'nt', '_PEB *'
) : host.namespace.Debugger.State.PseudoRegisters.General.peb,
pnt = peb.ApiSetMap.address,
api_set_namespace = read_struct([
'Version', 'Size', 'Flags', 'Count', 'EntryOffset', 'HashOffset', 'HashFactor'
], pnt);
for (let pasne = pnt.add(api_set_namespace.EntryOffset),
ofs_v = 0, i = 0; i < api_set_namespace.Count; ofs_v += 24, i++) {
let entry = read_struct([ // API_SET_NAMESPACE_ENTRY
'Flags', 'NameOffset', 'NameLength', 'HashedLength', 'ValueOffset', 'ValueCount'
], pasne.add(ofs_v));
let name = read_string(pnt.add(entry.NameOffset), entry.NameLength),
stat = 0 !== (entry.Flags & 1) ? 'true' : 'false',
vals = [];
for (let pasve = pnt.add(entry.ValueOffset),
ofs_e = 0, j = 0; j < entry.ValueCount; ofs_e += 20, j++) {
let value = read_struct([
'Flags', 'NameOffset', 'NameLength', 'ValueOffset', 'ValueLength'
], pasve.add(ofs_e));
vals.push(read_string(pnt.add(value.ValueOffset), value.ValueLength));
}
yield new ApiSetEnrty(name, stat, vals);
}
}
function initializeScript() {
return [new host.functionAlias(EnumerateApiSetEntries, 'apiset')]
}
Хотя в многострочном комментарии кода описано что к чему, добавлю: может потребоваться ввести полный путь до сценария (слэши
должны экранироваться). Например:
C:\dbg> cdb notepad
...
0:000> .scriptload E:\\dbg\\extensions\\apiset.js
JavaScript script successfully loaded from 'E:\dbg\extensions\apiset.js'
0:000> dx -g @$apiset()
============================================================================================================================
= = Entry = Sealed = Points =
============================================================================================================================
= [0x0] : [object Object] - api-ms-onecoreuap-print-render-l1-1-0 - true - printrenderapihost.dll =
= [0x1] : [object Object] - api-ms-win-appmodel-identity-l1-2-0 - true - kernel.appcore.dll =
= [0x2] : [object Object] - api-ms-win-appmodel-runtime-internal-l1-1-7 - true - kernel.appcore.dll =
...