The sample code below demonstrates verbose logging across multiple iOS logging APIs, including NSLog, print, debugPrint, dump, and Apple Unified Logging via Logger, during authentication, networking, storage access, and error-handling. These code paths are designed to produce verbose debug and error output in the compiled binary.
The sample includes logs exposing an internal API endpoint, a username, a mock session token, cached profile usage, error object contents, stack traces, internal module names, authentication flow details, validation logic, and network-related configuration details.
Open the app binary with radare2 (iOS) with the -i option to run the Radare2 script. The script first identifies cross references to the logging API imports, and then disassembles a selection of those call sites to recover the actual log messages. At each call site the message string is loaded into a register by an adrp/add pair right before the bl to the logging API, and Radare2 resolves that pointer and annotates it with the literal string, so you can read exactly what is logged.
escr.color=0escr.interactive=falseebin.relocs.apply=trueebin.cache=trueesearch.in=io.maps.xeasm.bytes=trueeasm.var=false?e===AnalyzingiOSBinaryforVerboseLogging===?e?e[*]Crossreferencestologgingrelatedimportsaxt@@sym.imp.*~NSLogaxt@@sym.imp.*~printaxt@@sym.imp.*~debugPrintaxt@@sym.imp.*~dumpaxt@@sym.imp.*~os_logaxt@@sym.imp.*~Loggeraxt@@sym.imp.*~_os_log_implaxt@@sym.imp.*~os_log_type_enabled?e# The xrefs above only prove the logging APIs are referenced. To show WHAT is# actually logged, disassemble each full call site from the string load up to# the logging call. The message is loaded into a register with an `adrp`/`add`# pair, r2 resolves that pointer and annotates it with the literal string, and a# few instructions later that register is passed as an argument to the `bl` into# the logging API. Reading the snippet top-to-bottom shows the string flowing# into the log call. The instruction count after each `pd` spans exactly from the# `adrp` to the `bl`; with `asm.bytes=true` the raw opcode bytes are shown too.?e[*]Recoveredlogmessagecontents?e(fulldisassemblyfromthestringloadtotheloggingcall)?e?e"=== NSLog -> internal API endpoint (mastgTest) ==="pd11@0x100006864?e?e"=== print -> username (performLogin) ==="pd21@0x1000048c4?e?e"=== debugPrint -> mock session token literal (performLogin) ==="pd16@0x10000498c?e?e"=== print -> SSL pinning disabled (performNetworkRequest) ==="pd13@0x100004d44?e?e"=== Logger.debug -> password hashing algorithm (validateCredentials) ==="pd7@0x1000047a8?e?e"=== NSLog -> error code & internal module (performLogin) ==="pd7@0x100004a7c?e?e[*]Done
run.sh
1234
#!/bin/bash# Run radare2 static analysis on the binaryr2-ebin.relocs.apply=true-q-iverbose_logging.r2-AMASTestApp>output.txt
The output has two parts. The first lists cross references to multiple logging APIs, and the second shows the disassembly of selected call sites with the recovered log message strings.
===AnalyzingiOSBinaryforVerboseLogging===[*]Crossreferencestologgingrelatedimportssym.func.1000048380x100004a5c[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.1000048380x100004a78[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.1000048380x100004a94[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.100005fb40x1000060b0[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.100005fb40x100006190[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.100005fb40x100006260[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.100005fb40x100006514[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.100005fb40x1000065c8[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.1000068400x10000688c[CALL:--x]blsym.imp.Foundation.NSLogCVarArg_...dtF_sym.func.1000048380x100004914[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004c78[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004cc8[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004d1c[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004d74[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004dcc[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004ed8[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004be80x100004f2c[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004f500x100005324[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004f500x100005454[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004f500x100005528[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100004f500x10000560c[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000056780x100005814[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000056780x1000058d0[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000056780x100005964[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100005a980x100005e70[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100005a980x100005f2c[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.100005a980x100005f88[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000068400x100006964[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000068400x100006a0c[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000068400x100006afc[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000068400x100006b50[CALL:--x]blsym.imp.print.separator.terminator.Stsym.func.1000048380x1000049c8[CALL:--x]blsym.imp.debugPrint.separator.terminator.Stsym.func.1000048380x100004a1c[CALL:--x]blsym.imp.debugPrint.separator.terminator.Stsym.func.100005fb40x100006298[CALL:--x]blsym.imp.dump.name.indent__String_...SgS3itlF_sym.func.10000465c0x100004708[CALL:--x]blsym.imp.os_log_type_t.addressor..debug_...vgZ_sym.func.10000465c0x100004774[CALL:--x]blsym.imp.os_log_type_t.addressor..debug_...vgZ_sym.func.100005fb40x1000062f4[CALL:--x]blsym.imp.os_log_type_t.addressor..error_...vgZ_sym.func.100005fb40x100006394[CALL:--x]blsym.imp.os_log_type_t.addressor..fault_...vgZ_sym.func.10000465c0x100004754[CALL:--x]blsym.imp._os_log_implsym.func.10000465c0x1000047c0[CALL:--x]blsym.imp._os_log_implsym.func.100005fb40x10000635c[CALL:--x]blsym.imp._os_log_implsym.func.100005fb40x1000064a0[CALL:--x]blsym.imp._os_log_implsym.func.10000465c0x100004718[CALL:--x]blsym.imp.os_log_type_enabledsym.func.10000465c0x100004784[CALL:--x]blsym.imp.os_log_type_enabledsym.func.100005fb40x100006304[CALL:--x]blsym.imp.os_log_type_enabledsym.func.100005fb40x1000063a8[CALL:--x]blsym.imp.os_log_type_enabledsym.func.10000465c0x100004700[CALL:--x]blsym.imp.os.Logger.logObject.OS_._...C0Cvgsym.func.10000465c0x10000476c[CALL:--x]blsym.imp.os.Logger.logObject.OS_._...C0Cvgsym.func.100005fb40x1000062ec[CALL:--x]blsym.imp.os.Logger.logObject.OS_._...C0Cvgsym.func.100005fb40x10000638c[CALL:--x]blsym.imp.os.Logger.logObject.OS_._...C0Cvgsym.func.10000465c0x1000046fc[CALL:--x]blsym.imp.os.Logger.subsystem.category__String_...tcfC_sym.func.100005fb40x1000062dc[CALL:--x]blsym.imp.os.Logger.subsystem.category__String_...tcfC_sym.func.10000465c0x10000468c[CALL:--x]blsym.imp.os.Logger...VMasym.func.100005fb40x100005fe4[CALL:--x]blsym.imp.os.Logger...VMasym.func.10000994c0x100009964[CALL:--x]blsym.imp.os.Logger...VMasym.func.1000099fc0x100009a14[CALL:--x]blsym.imp.os.Logger...VMasym.func.10000465c0x100004754[CALL:--x]blsym.imp._os_log_implsym.func.10000465c0x1000047c0[CALL:--x]blsym.imp._os_log_implsym.func.100005fb40x10000635c[CALL:--x]blsym.imp._os_log_implsym.func.100005fb40x1000064a0[CALL:--x]blsym.imp._os_log_implsym.func.10000465c0x100004718[CALL:--x]blsym.imp.os_log_type_enabledsym.func.10000465c0x100004784[CALL:--x]blsym.imp.os_log_type_enabledsym.func.100005fb40x100006304[CALL:--x]blsym.imp.os_log_type_enabledsym.func.100005fb40x1000063a8[CALL:--x]blsym.imp.os_log_type_enabled[*]Recoveredlogmessagecontents(fulldisassemblyfromthestringloadtotheloggingcall)===NSLog->internalAPIendpoint(mastgTest)===│0x100006864280000b0adrpx8,sym.imp.append_...ySSF_;0x10000b000│0x10000686808012a91addx8,x8,0xa80;0x10000ba80;"[DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login"│0x10000686c088100d1subx8,x8,0x20│0x10000687009098052movw9,0x48;'H'│0x100006874bc0280d2movx28,0x15│0x1000068781c00faf2movkx28,0xd000,lsl48│0x10000687c620000d0adrpx2,segment.__DATA_CONST;0x100014000│0x100006880423043f9ldrx2,[x2,0x660];[0x100014660:8]=0│;reloc._swiftEmptyArrayStorage│0x100006884800309aaorrx0,x28,x9│0x100006888010141b2orrx1,x8,0x8000000000000000│0x10000688c1d110094blsym.imp.Foundation.NSLogCVarArg_...dtF_;Foundation.NSLogCVarArg(...dtF)===print->username(performLogin)===│0x1000048c448000090adrpx8,0x10000c000│0x1000048c808810891addx8,x8,0x220;0x10000c220;"[DEBUG] performLogin() called with username:"│0x1000048cc088100d1subx8,x8,0x20│0x1000048d0080141b2orrx8,x8,0x8000000000000000│0x1000048d469760091addx9,x19,0x1d│0x1000048d8e92301a9stpx9,x8,[var_10h]│0x1000048dcf4430091addx20,sp,0x10│0x1000048e0e00319aamovx0,x25│0x1000048e4e10318aamovx1,x24│0x1000048e8c6190094blsym.imp.append_...ySSF_;append(...ySSF)│0x1000048ece82741a9ldpx8,x9,[var_10h]│0x1000048f09b000090adrpx27,segment.__DATA_CONST;0x100014000│0x1000048f47b9742f9ldrx27,[x27,0x528];[0x100014528:8]=0│;reloc....SSN│0x1000048f85b1f00f9strx27,[x26,0x38]│0x1000048fc482702a9stpx8,x9,[x26,0x20]│0x100004900e0031aaamovx0,x26│0x10000490401048052movw1,0x20│0x1000049080220fcd2movx2,-0x1f00000000000000│0x10000490c43018052movw3,0xa│0x1000049100420fcd2movx4,-0x1f00000000000000│0x100004914001a0094blsym.imp.print.separator.terminator.St===debugPrint->mocksessiontokenliteral(performLogin)===│0x10000498c280000f0adrpx8,sym.imp.append_...ySSF_;0x10000b000│0x10000499008013391addx8,x8,0xcc0;0x10000bcc0;"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"│0x100004994088100d1subx8,x8,0x20│0x10000499860520091addx0,x19,0x14│0x10000499c010141b2orrx1,x8,0x8000000000000000│0x1000049a0f4430091addx20,sp,0x10│0x1000049a497190094blsym.imp.append_...ySSF_;append(...ySSF)│0x1000049a8e82741a9ldpx8,x9,[var_10h]│0x1000049acdb1e00f9strx27,[x22,0x38]│0x1000049b0c82602a9stpx8,x9,[x22,0x20]│0x1000049b4e00316aamovx0,x22│0x1000049b801048052movw1,0x20│0x1000049bc0220fcd2movx2,-0x1f00000000000000│0x1000049c043018052movw3,0xa│0x1000049c40420fcd2movx4,-0x1f00000000000000│0x1000049c8ac190094blsym.imp.debugPrint.separator.terminator.St===print->SSLpinningdisabled(performNetworkRequest)===│0x100004d4448000090adrpx8,0x10000c000│0x100004d4808010591addx8,x8,0x140;0x10000c140;"[DEBUG] SSL pinning: disabled"│0x100004d4c088100d1subx8,x8,0x20│0x100004d50080141b2orrx8,x8,0x8000000000000000│0x100004d54151c00f9strx21,[x0,0x38]│0x100004d5829018052movw9,9│0x100004d5c490309aaorrx9,x26,x9│0x100004d60092002a9stpx9,x8,[x0,0x20]│0x100004d6401048052movw1,0x20│0x100004d680220fcd2movx2,-0x1f00000000000000│0x100004d6c43018052movw3,0xa│0x100004d700420fcd2movx4,-0x1f00000000000000│0x100004d74e8180094blsym.imp.print.separator.terminator.St===Logger.debug->passwordhashingalgorithm(validateCredentials)===│0x1000047a863000090adrpx3,section.16.__TEXT.__oslogstring;0x100010000│0x1000047ac63800191addx3,x3,0x60│0x1000047b0421f0012andw2,w26,0xff│0x1000047b4e10319aamovx1,x25│0x1000047b8e4031baamovx4,x27│0x1000047bc45008052movw5,2│0x1000047c0731a0094blsym.imp._os_log_impl===NSLog->errorcode&internalmodule(performLogin)===│0x100004a7c48000090adrpx8,0x10000c000│0x100004a8008010b91addx8,x8,0x2c0;0x10000c2c0;"[DEBUG] Error code: AUTH_001, Module: AuthenticationService.validateCredentials()"│0x100004a84088100d1subx8,x8,0x20│0x100004a8860060191addx0,x19,0x41│0x100004a8c010141b2orrx1,x8,0x8000000000000000│0x100004a90e20314aamovx2,x20│0x100004a949b180094blsym.imp.Foundation.NSLogCVarArg_...dtF_;Foundation.NSLogCVarArg(...dtF)[*]Done
The cross references show how often each logging API is reached:
9 binary xrefs to Foundation.NSLog... (the sample uses NSLog(...) 10 times).
22 binary xrefs to print.separator.terminator (the sample uses print(...) 23 times).
2 binary xrefs to debugPrint.separator.terminator (the sample uses debugPrint(...) 2 times).
1 binary xref to dump.name.indent... (the sample uses dump(...) 1 time).
2 binary xrefs to Logger.subsystem.category... (the sample uses Logger(...) 2 times).
logger.debug, logger.error, and logger.fault are used 4 times in the sample and result in:
4 xrefs to Logger.logObject...
4 xrefs to _os_log_impl
4 xrefs to os_log_type_enabled
4 log type xrefs: 2 debug, 1 error, 1 fault
Note that the number of logging calls in the source code and the number of binary xrefs do not always match exactly. In this case, NSLog and print each show one fewer xref than the number of source calls. That can happen because of compiler optimizations, inlining, or code generation details in Swift.
You'll notice that even though we aren't calling the old C-style os_log(...) API directly, since we are using Logger, and Logger is part of Apple's Unified Logging system, we see references to os_log. Under the hood, Swift logging relies on the unified logging machinery, which is why lower-level logging symbols appear in the compiled binary.
The second part of the output goes beyond confirming that the APIs are referenced and shows the literal message strings recovered from the call sites. Each block is the full disassembly window from the string load down to the logging call (with asm.bytes=true, the raw opcode bytes are shown alongside each instruction), so the data flow is explicit end to end: an adrp/add pair computes a pointer into the __cstring (or __oslogstring) section, Radare2 resolves it and prints the string as a comment (for example ; 0x10000ba80 ; "[DEBUG] Attempting to connect to API endpoint: https://internal-api.example.com/v2/auth/login"), the pointer is moved through a few argument-setup instructions, and the same register is then handed to the bl into the logging API that closes the window. Reading each snippet top to bottom shows the string flowing into the log call. The recovered content includes an internal API endpoint, the username, a mock session token (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9), the disabled SSL pinning state, the password hashing algorithm, and an internal error code and module name, all of which expose implementation details.
The test fails because the app contains implemented logging paths that record verbose diagnostic and error-related information, rather than merely linking against or referencing logging APIs.
This was determined by reverse engineering the binary in two steps. First, cross references to the logging APIs show that authentication, networking, and error-handling code paths reach NSLog, print, debugPrint, dump, and unified logging (Logger/os_log). Second, disassembling those call sites recovers the literal message strings that are passed to the logging functions, so the conclusion is not based on the mere presence of logging APIs but on the actual content that is logged. The recovered strings confirm that the compiled app emits sensitive implementation details, including an internal API endpoint, a username, a mock session token, the SSL pinning state, the password hashing algorithm, and an internal error code and module name.
The disassembly recovers the static string operands of each logging call. Values that are only known at runtime, such as the interpolated results of generateMockToken() or Thread.callStackSymbols, are not resolved by static analysis; to capture those concrete values you can use dynamic analysis and runtime log capture, see Implementation Details Exposed in App Logs.