As with most ideas, this one also took shape out of necessity to reduce manual work and dependencies in various scenarios. This blog post shows one of the many ways to read SMS messages from a jailbroken iPhone and send it as an email. There are ways to do this using a few Cydia Apps but they usually require you to register for an account or pay for the service which was less than ideal for me.
- iOS 5.1.1 (9B206) - Other versions may work as well
- Python 2.7.3 to 3 via Cydia (cydia.radare.org)
- SQLite 3.x via Cydia (cydia.radare.org)
- adv-cmds via Cydia (apt.saurik.com)
SMS StorageiOS stores a lot of data in sqlite databases which, in most cases, can be identified by their “.db” extension. SMS messages are stored in the following files:
/var/mobile/Library/SMS/sms.db /var/mobile/Library/SMS/sms.db-shm /var/mobile/Library/SMS/sms.db-wal
sms.db-walis a "Write Ahead Log" which is responsible for transactional behavior, while the
sms.db-shmis an "Associate File" which is required to read
sms.db-waland the original
sms.dbis the main file that retains most data, however these files are temporary in nature. The last received SMS message will go into
sms.db-waluses a different format on top of the standard sqlite structure as the
sms.db. All three files are read with a single
connect()function call from the sqlite API.
Reading the SMS DatabaseFirst task at hand is to read
sms.dbfile and analyze the database to find out how iOS is storing SMS messages. For whatever reason many of the sqlite3 utilities seem to have problems opening the file.
Sqlite3.exe and SQLite Database BrowserAlthough the initial import worked using
sqlite3.exeon Windows, attempts to query the
sms.dbfile failed. I also tried SQLite Database Browser which resulted in the below error.
Cydia’s sqlite3 binaryWe also tried to read the database file from within iOS using the sqlite3 binary that came with Cydia which proved to be futile:
Text EditorWith all of the utilities having problems reading the file, I decided to just open the file using a text editor to determine if there was something wrong with it. Everything looked fine, so I ran through the file looking for
CREATEstatements to determine where messages were stored which produced the following structure:
CREATE TABLE message (ROWID INTEGER PRIMARY KEY AUTOINCREMENT, address TEXT, date INTEGER, text TEXT, flags INTEGER, replace INTEGER, svc_center TEXT, group_id INTEGER, association_id INTEGER, height INTEGER, UIFlags INTEGER, version INTEGER, subject TEXT, country TEXT, headers BLOB, recipients BLOB, read INTEGER, madrid_attributedBody BLOB, madrid_handle TEXT, madrid_version INTEGER, madrid_guid TEXT, madrid_type INTEGER, madrid_roomname TEXT, madrid_service TEXT, madrid_account TEXT, madrid_account_guid TEXT, madrid_flags INTEGER, madrid_attachmentInfo BLOB, madrid_url TEXT, madrid_error INTEGER, is_madrid INTEGER, madrid_date_read INTEGER, madrid_date_delivered INTEGER);
With a potential idea of where SMS messages might be stored, I decided to use Python’s sqlite API to query the database directly.
smsDBQuery.pyuses the standard SQLite API to connect to the
sms.dband fetch all the unread messages using the below query:
SELECT text from message where read=0 order by date desc
To use the
smsDBQuery.py, copy it to your device’s
/var/mobile/Library/SMS/directory and run it as follows:
What’s interesting to note is that the
sms.dbcontains even very old messages that aren’t displayed on the device. This is because
sms.db-walretains the latest state for the device’s UI - so only a subset of messages are shown.
Catching New Entries and Sending EmailWe can use the SQL
TRIGGERstatement to catch insert events on the
messagetable when new SMS messages are received. Then our python script will take that message and send an email. We've created the following github repo for all the code:
- Create a temporary
message2table in the original database that is a subset of the main table
- Write a
TRIGGERon insert event of the database and attach it to the main SMS table. The
TRIGGERshould read the latest message and insert it into the
message2table without with altering any content in the original
- Have a secondary script regularly monitor the
message2table and send an email containing the message contents when a new entry is added. We’ll use the
emailsentflag to track state
smsCreateTrigger.pysmsCreateTrigger.py will create the database trigger and the
message2table. You’ll only need to run this once to get the database set up. I’d recommend backing up your
sms.dbjust in case and if you get any errors thoroughly inspect them. If you have any problems you can uncomment the DROP statements (and comment the
CREATE) to clean up the
smsWatcher.pysmsWatcher.py should be run in the background and will poll the
message2table for new entries. Once it sees one, it’ll take the message and send out an email via SMTP. You’ll need to manually set the following variables within the script to the variables applicable to your setup.
fromaddr : 'firstname.lastname@example.org' toaddrs : 'email@example.com' username : 'abc' password : '****' server : smtplib.SMTP('smtp.gmail.com:587') smsfromaddress :('AXARWINF','6564567890',)
Note that we’re only forwarding messages from a specific address. If you’d like to forward all messages simply modify the
SELECTstatement to not use the address field.
With all your variables set up, you can run the
smsWatcherprocess, be sure only one
smsWatcherprocess is running at a time:
python smsWatcher.py &