Skip to content

Commit

Permalink
Make DLL unpacking more reliable
Browse files Browse the repository at this point in the history
  • Loading branch information
ergrelet committed Aug 19, 2023
1 parent 95c8dc6 commit 1543211
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Changelog

## [Unreleased]
### Fixed
- Improve reliability of DLL unpacking

## [0.4.0] - 2023-08-14
### Added
Expand Down
27 changes: 9 additions & 18 deletions unlicense/resources/frida.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ let oepReached = false;
// DLLs-related
let skipDllOepInstr32 = null;
let skipDllOepInstr64 = null;
let dllOepCandidate = null;

// TLS-related
let skipTlsInstr32 = null;
Expand Down Expand Up @@ -125,6 +124,8 @@ function registerExceptionHandler(dumpedModule, expectedOepRanges, moduleIsDll)
}
}

const ldrUnlockLoaderLockAddr = Module.findExportByName('ntdll', 'LdrUnlockLoaderLock');
const ldrUnlockLoaderLock = new NativeFunction(ldrUnlockLoaderLockAddr, 'uint32', ['uint32', 'pointer']);
let expectionHandled = false;
expectedOepRanges.forEach((oepRange) => {
const sectionStart = dumpedModule.base.add(oepRange[0]);
Expand All @@ -145,15 +146,19 @@ function registerExceptionHandler(dumpedModule, expectedOepRanges, moduleIsDll)
}

if (moduleIsDll) {
// Save the potential OEP and and skip `DllMain` (`DLL_PROCESS_ATTACH`).
// Report the potential OEP
// Note: When dumping DLLs we have to release the loader
// lock before starting to dump.
// Other threads might call `DllMain` with the `DLL_THREAD_ATTACH`
// or `DLL_THREAD_DETACH` reasons later so we also skip the `DllMain`
// even after the OEP has been reached.
if (!oepReached) {
const threadId = Process.getCurrentThreadId();
ldrUnlockLoaderLock(0, ptr(threadId << 16));

log(`OEP found (thread #${threadId}): ${oepCandidate}`);
dllOepCandidate = oepCandidate;
// Note: never returns
notifyOepFound(dumpedModule, oepCandidate);
}

skipDllEntryPoint(exp.context);
Expand All @@ -163,6 +168,7 @@ function registerExceptionHandler(dumpedModule, expectedOepRanges, moduleIsDll)

// Report the potential OEP
log(`OEP found (thread #${threadId}): ${oepCandidate}`);
// Note: never returns
notifyOepFound(dumpedModule, oepCandidate);
}
});
Expand Down Expand Up @@ -242,21 +248,6 @@ rpc.exports = {
dumpedModule = Process.findModuleByName(moduleName);
}

// Hook `ntdll.LdrLoadDll` on exit to get called at a point where the
// loader lock is released. Needed to unpack (32-bit) DLLs.
const loadDll = Module.findExportByName('ntdll', 'LdrLoadDll');
const loadDllListener = Interceptor.attach(loadDll, {
onLeave: function (_args) {
// If `dllOepCandidate` is set, proceed with the dumping
// but only once (for our target). Then let other executions go
// through as it's not DLLs we're intersted in.
if (dllOepCandidate != null && !oepReached) {
notifyOepFound(dumpedModule, dllOepCandidate);
}
}
});
oepTracingListeners.push(loadDllListener);

let exceptionHandlerRegistered = false;
const ntProtectVirtualMemory = Module.findExportByName('ntdll', 'NtProtectVirtualMemory');
if (ntProtectVirtualMemory != null) {
Expand Down

0 comments on commit 1543211

Please sign in to comment.