├── README.md ├── printGetPostVariables.py └── parseMapMyRide.py /README.md: -------------------------------------------------------------------------------- 1 | # mobileForensics 2 | 3 | The objective of this repository is to provide tools to help in mobile forensics investigations. 4 | 5 | parseMapMyRide 6 | Extracts Geo location data from parseMapMyRide workout application database workout.db as well as user related information extracted from mmkd_user file. These files are located in /apps/com.mapmyride.android2/db. 7 | 8 | Sample usage: 9 | 10 | python parseMapMyRide.py 11 | Workout(s) extracted: 3 12 | Entries with GPS location extracted: 1407 Import the file workoutGPS.txt into excel using ; as delimiter. 13 | Extracted user data into userMapMyRide.csv 14 | -------------------------------------------------------------------------------- /printGetPostVariables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Author David Bernal 3 | ''' 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | ''' 15 | 16 | #This program is useful to debug web applicatons, it sets up a web server and prints all the POST parameters sent as well as all the headers. 17 | 18 | from urlparse import urlparse, parse_qs 19 | import BaseHTTPServer 20 | import time 21 | 22 | HOST_NAME = '0.0.0.0' 23 | PORT_NUMBER = 80 24 | 25 | class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): 26 | 27 | def do_HEAD(s): 28 | s.send_response(404) 29 | s.send_header("Content-type", "text/html") 30 | s.end_headers() 31 | 32 | def do_GET(s): 33 | """Respond to a GET request.""" 34 | print "GET request" 35 | s.send_response(200) 36 | s.send_header("Content-type", "text/html") 37 | s.end_headers() 38 | 39 | query_components = parse_qs(urlparse(s.path).query) 40 | 41 | print s.headers 42 | #print query_components 43 | print urlparse(s.path).query 44 | for component in query_components.keys(): 45 | print "component: " + component + " value: " + str(query_components[component]) 46 | print "-------" 47 | 48 | s.wfile.write("

Response

") 49 | return 50 | 51 | def do_POST(s): 52 | """Respond to a POST request.""" 53 | print "POST request" 54 | s.send_response(200) 55 | s.send_header("Content-type", "text/html") 56 | s.end_headers() 57 | 58 | length = int(s.headers.getheader('content-length')) 59 | field_data = s.rfile.read(length) 60 | query_components = parse_qs(field_data) 61 | 62 | s.wfile.write("

Response

") 63 | print s.headers 64 | 65 | for component in query_components.keys(): 66 | value = query_components[component][0] 67 | 68 | print "component: " + component + " -- value: " + str(value) 69 | 70 | if __name__ == '__main__': 71 | server_class = BaseHTTPServer.HTTPServer 72 | httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler) 73 | print time.asctime(), "Inicio - %s:%s" % (HOST_NAME, PORT_NUMBER) 74 | try: 75 | httpd.serve_forever() 76 | except KeyboardInterrupt: 77 | pass 78 | -------------------------------------------------------------------------------- /parseMapMyRide.py: -------------------------------------------------------------------------------- 1 | # Author David Bernal 2 | ''' 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | ''' 16 | 17 | # Parser for mapMyRide appliations, extracts user, workout and GPS data for every workout. 18 | import sqlite3 19 | import os 20 | import sys 21 | import time 22 | 23 | def epocToUTC(epoc): 24 | return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(float(epoc))) 25 | 26 | mapMyRideWorkoutDB = "workout.db" 27 | 28 | if not os.path.isfile(mapMyRideWorkoutDB): 29 | print "Please place the file " + mapMyRideWorkoutDB + " on the same folder than " + sys.argv[0] + " and try again." 30 | sys.exit(1) 31 | 32 | f = open("workoutSummary.csv", "w") 33 | db = sqlite3.connect(mapMyRideWorkoutDB) 34 | res = db.execute("select localid, name, starttime, endtime, notes from workouts") 35 | col_name_list = [tuple[0] for tuple in res.description] 36 | f.write(";".join(col_name_list)) 37 | 38 | workoutCount = 0 39 | for row in res: 40 | workoutCount += 1 41 | f.write("\n" + str(row[0]) + ";" + row[1] + ";" + epocToUTC(row[2][:10]) + ";" + epocToUTC(row[3][:10]) + ";" + str(row[4]) ) 42 | f.close() 43 | print "Workout(s) extracted: " + str(workoutCount) 44 | 45 | f = open("workoutGPS.txt", "w") 46 | res = db.execute("select localid, timestamp, longitude, latitude, altitude from timeseries") 47 | col_name_list = [tuple[0] for tuple in res.description] 48 | f.write(";".join(col_name_list) + ";Google maps URL (Generated by the script)") 49 | 50 | timeSeriesCount = 0 51 | for row in res: 52 | timeSeriesCount += 1 53 | f.write("\n" + row[0] + ";" + epocToUTC(str(row[1])[:10]) + ";" + str(row[2]) + ";" + str(row[3]) + ";" + str(row[4]) + ";http://maps.google.com/?q=" + str(row[3]) +","+str(row[2])) 54 | f.close() 55 | 56 | print "Entries with GPS location extracted: " + str(timeSeriesCount) + " Import the file workoutGPS.txt into excel using ; as delimiter." 57 | 58 | mapMyRideUserDB = "mmdk_user" 59 | 60 | if not os.path.isfile(mapMyRideUserDB): 61 | print "To extract user data please place the file " + mapMyRideUserDB + " on the same folder than " + sys.argv[0] + " and try again." 62 | sys.exit(1) 63 | 64 | f = open("userMapMyRide.csv", "w") 65 | db = sqlite3.connect(mapMyRideUserDB) 66 | res = db.execute("select username, email, first_name, last_name, birthdate, height, weight, gender, date_joined, location_country, profile_image_medium from user_entity") 67 | col_name_list = [tuple[0] for tuple in res.description] 68 | f.write(",".join(col_name_list)) 69 | 70 | for row in res: 71 | f.write("\n" + row[0] + "," + row[1] + "," + row[2] + "," + row[3] + "," + str(row[4]) + "," + str(row[5])+ "," + str(row[6]) + "," + row[7] + "," + epocToUTC(str(row[8])[:10]) + "," + row[9] + "," + row[10]) 72 | f.close() 73 | print "Extracted user data into userMapMyRide.csv" --------------------------------------------------------------------------------