Mobile-Security-Framework-MobSF
Mobile-Security-Framework-MobSF copied to clipboard
SYMBOLS STRIPPED False positive
ENVIRONMENT
OS and Version: MacOS 12.1
Python Version: Python 3.8.12
MobSF Version: 3.5.0
EXPLANATION OF THE ISSUE
False positive of SYMBOLS STRIPPED
STEPS TO REPRODUCE THE ISSUE
- Create a empty project in xcode
- Configure build settings per recommended:
To strip debugging symbols, set Strip Debug Symbols During Copy to YES, Deployment Postprocessing to YES, and Strip Linked Product to YES in project's build settings.

- Build and export the binary
- Check for debug symbols:
dsymutil --statistics test_stripped
warning: no debug symbols in executable (-arch arm64)
.debug_info section size (in bytes)
-------------------------------------------------------------------------------
Filename Object dSYM Change
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Total 0b 0b 0.00%
-------------------------------------------------------------------------------
-
Scan with MobFs
-
If I try to strip an external global symbol, it will throw an error:
z@Z-Macbook test.app % nm test_stripped | grep "_swift_allocObject"
U _swift_allocObject
z@Z-Macbook test.app % cat tobestripped
_swift_allocObject
z@Z-Macbook test.app % strip -R tobestripped test_stripped -o test_stripped2
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip: error: symbol: _swift_allocObject undefined and can't be stripped from: /Users/z/Library/Developer/Xcode/Archives/2022-03-03/test 03-03-2022, 21.35.xcarchive/Products/Applications/test.app/test_stripped
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip: error: symbols names listed in: tobestripped not in: /Users/z/Library/Developer/Xcode/Archives/2022-03-03/test 03-03-2022, 21.35.xcarchive/Products/Applications/test.app/test_stripped
_swift_allocObject
So, with an empty xcode project, it always failed due to symbols are not completely stripped.
I also found a post about it: https://lists.apple.com/archives/xcode-users/2016/Dec/msg00100.html
You’ll note that if you leave out the step of defining a function that
calls printf(), Archive succeeds successfully. When you add that call to
printf(), the compiler emits a call to an entry in the indirect symbol
table that will be emitted by the linker. If you strip that table, that
call will wind up going nowhere.
LOG FILE
[INFO] 03/Mar/2022 15:25:41 -
__ __ _ ____ _____ _____ ____
| \/ | ___ | |__/ ___|| ___|_ _|___ / | ___|
| |\/| |/ _ \| '_ \___ \| |_ \ \ / / |_ \ |___ \
| | | | (_) | |_) |__) | _| \ V / ___) | ___) |
|_| |_|\___/|_.__/____/|_| \_/ |____(_)____/
[INFO] 03/Mar/2022 15:25:41 - Mobile Security Framework v3.5.0 Beta
[INFO] 03/Mar/2022 15:25:41 - OS: Darwin
[INFO] 03/Mar/2022 15:25:41 - Platform: macOS-12.1-x86_64-i386-64bit
[INFO] 03/Mar/2022 15:25:41 - Dist: darwin 21.2.0
[INFO] 03/Mar/2022 15:25:41 - MobSF Basic Environment Check
[WARNING] 03/Mar/2022 15:25:41 - Dynamic Analysis related functions will not work.
Make sure a Genymotion Android VM/Android Studio Emulator is running before performing Dynamic Analysis.
[INFO] 03/Mar/2022 15:25:42 - Checking for Update.
[WARNING] 03/Mar/2022 15:25:42 - A new version of MobSF is available, Please update to 3.5.2 from master branch.
[INFO] 03/Mar/2022 15:25:43 - MIME Type: application/octet-stream FILE: test_stripped.ipa
[INFO] 03/Mar/2022 15:25:43 - Performing Static Analysis of iOS IPA
[INFO] 03/Mar/2022 15:25:43 - iOS Static Analysis Started
[INFO] 03/Mar/2022 15:25:43 - iOS Binary (IPA) Analysis Started
[INFO] 03/Mar/2022 15:25:43 - Generating Hashes
[INFO] 03/Mar/2022 15:25:43 - Extracting IPA
[INFO] 03/Mar/2022 15:25:43 - Unzipping
[INFO] 03/Mar/2022 15:25:43 - Get Files, BIN Plist -> XML, and Normalize
[INFO] 03/Mar/2022 15:25:43 - iOS Info.plist Analysis Started
[INFO] 03/Mar/2022 15:25:43 - Finding Info.plist in iOS Binary
[INFO] 03/Mar/2022 15:25:43 - Checking Permissions
[INFO] 03/Mar/2022 15:25:43 - Checking for Insecure Connections
[INFO] 03/Mar/2022 15:25:43 - Fetching Details from App Store: com.ducna.test
[WARNING] 03/Mar/2022 15:25:43 - Unable to get app details.
[INFO] 03/Mar/2022 15:25:43 - Starting Binary Analysis
[INFO] 03/Mar/2022 15:25:43 - Running MachO Analysis on test
[INFO] 03/Mar/2022 15:25:43 - Getting Binary Information
[INFO] 03/Mar/2022 15:25:43 - Dumping classes
[INFO] 03/Mar/2022 15:25:43 - Running class-dump-swift against binary
[INFO] 03/Mar/2022 15:25:44 - Running class-dump against binary
[INFO] 03/Mar/2022 15:25:44 - Running strings against the Binary
[INFO] 03/Mar/2022 15:25:44 - Fetching icon path
[WARNING] 03/Mar/2022 15:25:44 - Could not find app icon
[INFO] 03/Mar/2022 15:25:44 - Starting IPA URL and Email Extraction
[INFO] 03/Mar/2022 15:25:44 - Performing Malware Check on extracted Domains
[INFO] 03/Mar/2022 15:25:45 - Maltrail Database is up-to-date
[INFO] 03/Mar/2022 15:25:45 - Finished URL and Email Extraction
[INFO] 03/Mar/2022 15:25:47 - Trackers Database is up-to-date
[INFO] 03/Mar/2022 15:25:47 - Detecting Trackers from Domains
[INFO] 03/Mar/2022 15:25:47 - Detecting Firebase URL(s)
[INFO] 03/Mar/2022 15:25:47 - Connecting to DB
[INFO] 03/Mar/2022 15:25:47 - Saving to Database
[ERROR] 03/Mar/2022 15:25:47 - Updating DB
Traceback (most recent call last):
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: table StaticAnalyzer_staticanalyzerios has no column named TRACKERS
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/mobsf/StaticAnalyzer/views/ios/db_interaction.py", line 165, in save_or_update
StaticAnalyzerIOS.objects.create(**values)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/query.py", line 514, in create
obj.save(force_insert=True, using=self.db)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 806, in save
self.save_base(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 857, in save_base
updated = self._save_table(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1000, in _save_table
results = self._do_insert(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1041, in _do_insert
return manager._insert(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1434, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1621, in execute_sql
cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 103, in execute
return super().execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: table StaticAnalyzer_staticanalyzerios has no column named TRACKERS
[INFO] 03/Mar/2022 15:25:47 - iOS Static Analysis Started
[INFO] 03/Mar/2022 15:25:47 - iOS Binary (IPA) Analysis Started
[INFO] 03/Mar/2022 15:25:47 - Generating Hashes
[INFO] 03/Mar/2022 15:25:47 - Extracting IPA
[INFO] 03/Mar/2022 15:25:47 - Unzipping
[INFO] 03/Mar/2022 15:25:47 - Get Files, BIN Plist -> XML, and Normalize
[INFO] 03/Mar/2022 15:25:47 - iOS Info.plist Analysis Started
[INFO] 03/Mar/2022 15:25:47 - Finding Info.plist in iOS Binary
[INFO] 03/Mar/2022 15:25:47 - Checking Permissions
[INFO] 03/Mar/2022 15:25:47 - Checking for Insecure Connections
[INFO] 03/Mar/2022 15:25:47 - Fetching Details from App Store: com.ducna.test
[WARNING] 03/Mar/2022 15:25:47 - Unable to get app details.
[INFO] 03/Mar/2022 15:25:47 - Starting Binary Analysis
[INFO] 03/Mar/2022 15:25:47 - Running MachO Analysis on test
[INFO] 03/Mar/2022 15:25:47 - Getting Binary Information
[INFO] 03/Mar/2022 15:25:47 - Dumping classes
[INFO] 03/Mar/2022 15:25:47 - Running class-dump-swift against binary
[INFO] 03/Mar/2022 15:25:47 - Running class-dump against binary
[INFO] 03/Mar/2022 15:25:47 - Running strings against the Binary
[INFO] 03/Mar/2022 15:25:47 - Fetching icon path
[WARNING] 03/Mar/2022 15:25:47 - Could not find app icon
[INFO] 03/Mar/2022 15:25:47 - Starting IPA URL and Email Extraction
[INFO] 03/Mar/2022 15:25:47 - Performing Malware Check on extracted Domains
[INFO] 03/Mar/2022 15:25:48 - Maltrail Database is up-to-date
[INFO] 03/Mar/2022 15:25:48 - Finished URL and Email Extraction
[INFO] 03/Mar/2022 15:25:50 - Trackers Database is up-to-date
[INFO] 03/Mar/2022 15:25:50 - Detecting Trackers from Domains
[INFO] 03/Mar/2022 15:25:50 - Detecting Firebase URL(s)
[INFO] 03/Mar/2022 15:25:50 - Connecting to DB
[INFO] 03/Mar/2022 15:25:50 - Saving to Database
[ERROR] 03/Mar/2022 15:25:50 - Updating DB
Traceback (most recent call last):
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: table StaticAnalyzer_staticanalyzerios has no column named TRACKERS
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/mobsf/StaticAnalyzer/views/ios/db_interaction.py", line 165, in save_or_update
StaticAnalyzerIOS.objects.create(**values)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/query.py", line 514, in create
obj.save(force_insert=True, using=self.db)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 806, in save
self.save_base(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 857, in save_base
updated = self._save_table(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1000, in _save_table
results = self._do_insert(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/base.py", line 1041, in _do_insert
return manager._insert(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1434, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1621, in execute_sql
cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 103, in execute
return super().execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/utils.py", line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
File "/Users/z/Downloads/Mobile-Security-Framework-MobSF-3.5.0/venv/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py", line 477, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: table StaticAnalyzer_staticanalyzerios has no column named TRACKERS
👋 @zsecducna Issues is only for reporting a bug/feature request. For limited support, questions, and discussions, please join MobSF Slack channel Please include all the requested and relevant information when opening a bug report. Improper reports will be closed without any response.
Hey @ajinabraham Can you confirm that is this a valid issue?
I'm also seeing this exact same issue, is this considered valid?
@zsecducna Can you share some IPAs with these different stripping configurations?
@ajinabraham Are you still needing IPAs? I can provide an example of an IPA that exhibits this false positive if needed
That would be helpful.
@ajinabraham I've sent the IPA to your email.
The configurations are setup in XCode as follows:

Running the command below (on the content of the unzipped IPA) confirms no debugging symbols in the binary.


Hi with these config, I'm still getting this issue:
Any solution for this?
Hello is there any update about this issue?
Any update for this ?
I had a similar issue with my script and figured out the problem so I'd like to share my solution with you.
Responsible code for the check can be found at https://github.com/MobSF/Mobile-Security-Framework-MobSF/blob/master/mobsf/StaticAnalyzer/views/ios/macho_analysis.py#L226
def is_symbols_stripped(self):
for i in self.macho.symbols:
if i:
return False
return True
There are two problems:
- The check will return False (not stripped) if any symbol is found. Since stripping debugging symbols won't get rid of all symbols (thus the name stripping debug symbols), this will always return False. This means we need to introduce a check for the symbol type and only look for debug symbols.
- Stripping debug symbols in XCode (or also with 'strip') will reintroduce a hardcoded debug symbol 'radr://5614542' of the type 'OPT', which stands for 'Source File Option' and shouldn't have any impact. Being confused about this I started digging around and found that 'radr' is short for Radar and is Apples' bug tracking system that is used in-house, thus 'radr://5614542' specifies a ticket. If one looks closely in the source code of 'strip' at https://opensource.apple.com/source/cctools/cctools-751/misc/strip.c.auto.html, the reason odd behavior for this is documented and is about having a problem, that will arise with having an empty symbol list and too much effort to fix and thus this placeholder is inserted. This means you'll always end up with at least this one debug symbol and even if we would check for the symbol type, MobSF would say it is not stripped because it found one.
Knowing this, we come up with the following requirements the check has to perform:
- Checking the symbol type and only look at debug symbols.
- Filter out the placebo debug symbol introduced by the stripping process.
While researching how we can determine the symbol types I stumbled upon https://opensource.apple.com/source/xnu/xnu-201/EXTERNAL_HEADERS/mach-o/nlist.h. Symbols in the table have different fields and the n_type field of any entry is responsible for the type. The n_type entry is an unsigned char (1byte/11111111) and can have different masks, which decide different things. The first 3 bits (11100000 or 0xe0) make up the mask called N_STAB and if any of these bits is set, it is a symbolic debugging entry. This mask is what we are looking for.
Fixed code putting things together (checking the type and filter the placebo symbol):
def is_symbols_stripped(self):
filter_symbol = 'radr://5614542'
for i in self.macho.symbols:
if (i.type & 0xe0) > 0 and i.name.lower().strip() != filter_symbol:
return False
return True
In my tests this did the trick. I opened up a pull request for this: https://github.com/MobSF/Mobile-Security-Framework-MobSF/pull/2023
PS: If the tests in MobSF are really intended to look at all symbols and not only debug symbols this fix won't be the right solution. I think to check if 'Debugging Symbols' was chosen you can check the total amount of local symbols, it is most likely greater than 1 and the placeholder symbol will not be present. But it will have 1 local symbol (the placeholder symbol) if 'All Symbols' or 'Non-Global Symbols' was chosen. I'm currently unaware of how you could distinguish between the latter two reliably.
Nice work, @rustaska This is the perfect answer I want to hear! Thank you so much!!
Thanks for the excellent research @rustaska. I will review and get this PR merged soon.