
If you're writing or debugging Frida scripts and hit errors about Module.findBaseAddress or Memory.readU32 not working, this is for you. Frida 17 (May 2025) removed a bunch of static methods that older tutorials still reference. This guide shows exactly what broke and what to use instead: Process.findModuleByName() for module lookups, NativePointer instance methods for memory operations, and array returns instead of callback-style enumeration. It also catches naming conflicts like defining your own hexdump function, which now collides with Frida's built-in. The checklist at the end is genuinely useful for migration work. Honestly, this should have been in the official release notes with this level of detail.
$ npx -y skills add yfe404/frida-17-skill --skill frida-17 --agent claude-codeInstalls into .claude/skills of the current project.
This skill helps write and fix Frida scripts compatible with Frida 17.0.0 (released May 2025).
// OLD - No longer works in Frida 17
Module.findBaseAddress('libriver.so')
Module.getBaseAddress('libriver.so')
Module.findExportByName(null, 'open')
Module.findExportByName('libc.so', 'open')
Module.getExportByName(null, 'open')
Module.ensureInitialized('libc.so')
Module.enumerateExports('libc.so')
Module.enumerateSymbols('libc.so')
// NEW - Use Process and instance methods instead
var lib = Process.findModuleByName('libriver.so'); // returns Module or null
var lib = Process.getModuleByName('libriver.so'); // throws if not found
lib.base // module base address
lib.findExportByName('open') // returns address or null
lib.getExportByName('open') // throws if not found
lib.enumerateExports() // returns array
lib.enumerateSymbols() // returns array
// OLD - No longer works
Memory.readU32(ptr)
Memory.writeU32(ptr, value)
// NEW - Use NativePointer instance methods
ptr.readU32()
ptr.writeU32(value)
// OLD - Callback style removed
Process.enumerateModules({ onMatch: fn, onComplete: fn })
Process.enumerateModulesSync()
// NEW - Returns array directly
Process.enumerateModules()
The following are built-in Frida functions. Defining custom functions with these names causes:
TypeError: cannot define variable 'hexdump'
Reserved names:
hexdump - Use dumpHex instead for custom hex dump functionsptr - pointer constructor shorthandNULL - null pointer constant// BAD - conflicts with built-in
function hexdump(ptr, len) { ... }
// GOOD - use different name
function dumpHex(ptr, len) { ... }
Conversion:
toInt32() - cast to signed 32-bit integertoNumber() - convert to JavaScript numbertoString([radix]) - convert to stringNOT available:
toUInt32() - DOES NOT EXIST, use toInt32() for sizes < 2^31Memory reading:
readU8(), readS8(), readU16(), readS16()readU32(), readS32(), readU64(), readS64()readByteArray(length) - returns ArrayBufferreadPointer(), readCString(), readUtf8String()Memory writing:
writeU8(value), writeS8(value), etc.writeByteArray(bytes) - bytes must be ArrayBuffer or JS arraywritePointer(ptr), writeUtf8String(str)Pointer arithmetic:
add(rhs), sub(rhs), and(rhs), or(rhs), xor(rhs)shr(n), shl(n), not()isNull(), equals(rhs), compare(rhs)Java.perform(function() {
var MyClass = Java.use('com.example.MyClass');
// Hook with overload
MyClass.myMethod.overload('int', 'java.lang.String').implementation = function(a, b) {
console.log('Called with: ' + a + ', ' + b);
// Call original
return this.myMethod.overload('int', 'java.lang.String').call(this, a, b);
};
// Hook all overloads
MyClass.myMethod.overloads.forEach(function(overload) {
overload.implementation = function() {
return overload.apply(this, arguments);
};
});
});
Java byte[] handling:
Java byte arrays cannot be passed directly to Memory.alloc().writeByteArray().
Convert manually:
// BAD - throws "expected a buffer-like object"
var hex = dumpHex(Memory.alloc(javaByteArray.length).writeByteArray(javaByteArray), len);
// GOOD - iterate and convert
var hex = "";
for (var i = 0; i < javaByteArray.length; i++) {
hex += ("0" + (javaByteArray[i] & 0xff).toString(16)).slice(-2);
}
function waitForLibrary(libName, callback) {
var lib = Process.findModuleByName(libName);
if (lib) {
callback(lib.base);
return;
}
var pollInterval = setInterval(function() {
var lib = Process.findModuleByName(libName);
if (lib) {
clearInterval(pollInterval);
callback(lib.base);
}
}, 500);
}
var libc = Process.findModuleByName('libc.so');
var open = libc ? libc.findExportByName('open') : null;
if (open) {
Interceptor.attach(open, {
onEnter: function(args) {
console.log('open(' + args[0].readCString() + ')');
}
});
}
function dumpHex(ptr, len) {
if (!ptr || ptr.isNull()) return 'null';
try {
var bytes = ptr.readByteArray(len);
if (!bytes) return 'null';
var arr = new Uint8Array(bytes);
var hex = '';
for (var i = 0; i < arr.length; i++) {
hex += ('0' + arr[i].toString(16)).slice(-2);
}
return hex;
} catch (e) {
return 'error: ' + e;
}
}
When reviewing a Frida script, check for:
Module.findBaseAddress() -> Process.findModuleByName().baseModule.getBaseAddress() -> Process.getModuleByName().baseModule.findExportByName(null, name) -> Process.findModuleByName('libc.so').findExportByName(name)Module.findExportByName(lib, name) -> Process.findModuleByName(lib).findExportByName(name)Module.enumerateExports(lib) -> Process.getModuleByName(lib).enumerateExports()Module.enumerateSymbols(lib) -> Process.getModuleByName(lib).enumerateSymbols()Memory.readU32(ptr) -> ptr.readU32()toUInt32() -> toInt32() (toUInt32 never existed)function hexdump() -> function dumpHex() (name conflict)writeByteArray() -> manual hex conversionSponsors