First commit

This commit is contained in:
FlUxIuS 2018-06-12 21:52:11 +02:00
commit 6084eb30d6
24 changed files with 1662 additions and 0 deletions

247
README.md Normal file
View File

@ -0,0 +1,247 @@
Modmobmap
==========
Modmobmap is a tool aimed to retrieve information of cellular networks.
As shown in the first [presentation made at BeeRump 2018](https://www.rump.beer/2018/slides/modmobmap.pdf). This tool is able to retrieve information of 2G, 3G, 4G and more cellular network types with minimum requierement: only a phone with ServiceMode.
For the moment, the tool has only been tested and developped for the following devices:
- Samsung Galaxy S3 via [xgoldmon (Modmobmap's edition)](https://github.com/FlUxIuS/xgoldmon);
- Samsung Galaxy S4;
- Samsung Galaxy S5;
- Samsung Galaxy Note 2 with LTE;
But as it's compatible for XGold via Modmobmap's forked of *xgoldmon*, this will probably include the following devices too:
- Samsung Galaxy S4 GT-I9500 (this is the version without LTE!)
- Samsung Galaxy Nexus GT-I9250 (has to be rooted!)
- Samsung Galaxy S2 GT-I9100
- Samsung Galaxy Note 2 GT-N7100
Note that all devices should be rooted. In any other case, you will have to use the DFR technique by hand!
Also: Patches, or engines, for other devices are very much welcomed! ;)
Requirements
-------------
Here are the following requirements:
- Python 2 or 3;
- Last Android SDK to run ADB: https://developer.android.com/studio/#downloads;
- A compatible mobile phone;
- A valid/unvalid SIM card (just in case to provide an IMSI number).
How to use
----------
The tool is provided with a quick help that shows you the required argument as follows:
```
python modmobmap.py -h
usage: modmobmap.py [-h] [-m MODULE] [-n NETWORKS] [-o] [-s ANDROIDSDK]
[-a ATMODE] [-f FILE]
Mobile network mapping tool with cheap equipments
optional arguments:
-h, --help show this help message and exit
-m MODULE, --module MODULE
Module to use (e.g: "servicemode" by default)
-n NETWORKS, --networks NETWORKS
Networks in MCCMNC format splitted with commas
-o, --cached_operator
Use operator in cache to speed up the passive scan
-s ANDROIDSDK, --sdk ANDROIDSDK
Android SDK path
-a ATMODE, --at ATMODE
AT access mode. If host put something like
"/dev/ttyUSBxx. By default it uses ADB."
-f FILE, --file FILE File to parse. For the moment it could be used in
combination with AT mode host.
```
Assuming the Android SDK is installed in */opt/Android*, the tool can be quickly started as follows:
```
$ sudo python modmobmap.py
=> Requesting a list of MCC/MNC. Please wait, it may take a while...
Found 2 operator(s)
{u'20810': u'F SFR', u'20820': u'F-Bouygues Telecom'}
[+] Unregistered from current PLMN
[+] New cell detected [CellID/PCI-DL_freq (4XXX-81)]
Network type=2G
PLMN=208-10
ARFCN=81
[+] New cell detected [CellID/PCI-DL_freq (6XXXXXX-2950)]
Network type=3G
PLMN=208-20
Band=8
Downlink UARFCN=2950
Uplink UARFCN=2725
[+] New cell detected [CellID/PCI-DL_freq (3XX-6300)]
Network type=4G
PLMN=208-10
Band=20
Downlink EARFCN=6300
[+] New cell detected [CellID/PCI-DL_freq (3XX-2825)]
Network type=4G
PLMN=208-10
Band=7
Downlink EARFCN=2825
[+] New cell detected [CellID/PCI-DL_freq (3XX-1675)]
Network type=4G
PLMN=208-10
Band=3
Downlink EARFCN=1675
[...]
```
Note: If the Android SDK is installed anywhere else, you can use the *-s* parameter to specify its directory.
Speed-up the passive scan
---------------------------
When looking for operators, an AT command is sent to the modem. If you want to speed-up the scanning, you can hardcoded the operators to the following file `cache/operators.json`:
```
{
"20801": "Orange",
"20810": "F SFR",
"20815": "Free",
"20820": "F-Bouygues Telecom"
}
```
Only the MCC/MNC codes are inmportant. Then you can re-launch the tool as follows:
```
$ sudo python modmobmap.py -o
=> Requesting a list of MCC/MNC. Please wait, it may take a while...
Found 4 operators in cache, you choose to reuse them.
Found 4 operator(s)
{u'20810': u'F SFR', u'20820': u'F-Bouygues Telecom', u'20815': u'Free', u'20801': u'Orange'}
[+] Unregistered from current PLMN
[+] New cell detected [CellID/PCI-DL_freq (XXXX-10614)]
Network type=3G
PLMN=208-10
Band=1
Downlink UARFCN=10614
Uplink UARFCN=9664
[...]
[+] New cell detected [CellID/PCI-DL_freq (XXX-3501)]
Network type=4G
PLMN=208-20
Band=8
Downlink EARFCN=3501
[...]
[+] Unregistered from current PLMN
=> Changing MCC/MNC for: 20815
[+] New cell detected [CellID/PCI-DL_freq (XXX-2825)]
Network type=4G
PLMN=208-15
Band=7
Downlink EARFCN=2825
[...]
=> Changing MCC/MNC for: 20801
[+] New cell detected [CellID/PCI-DL_freq (XXXXX-3011)]
Network type=3G
PLMN=208-1
Band=8
Downlink UARFCN=3011
Uplink UARFCN=2786
[...]
```
Note we have been able to detect other cells the AT command *AT+COPS* did not returned.
A complet list of MCC and MNC codes could be retrieved anywhere on internet and in Wikipedia: https://en.wikipedia.org/wiki/Mobile_country_code
Focusing some operators
------------------------
It is possible to tell *Modmobmap* to only focuse on specific operators with the *-m* argument:
```
$ sudo python modmobmap.py -n 20801
=> Manual MCC/MNC processing...
Found 1 operator(s)
{'20801': '20801'}
[...]
=> Changing MCC/MNC for: 20801
[+] New cell detected [CellID/PCI-DL_freq (XXX-1675)]
Network type=4G
PLMN=208-01
Band=3
Downlink EARFCN=1675
[+] New cell detected [CellID/PCI-DL_freq (XXXXX-3011)]
Network type=3G
PLMN=208-1
Band=8
Downlink UARFCN=3011
Uplink UARFCN=2786
=> Changing network type for 3G only
[+] New cell detected [CellID/PCI-DL_freq (XXXXX-2950)]
Network type=3G
PLMN=208-1
Band=8
Downlink UARFCN=2950
Uplink UARFCN=2725
```
Using Modmobmap with xgoldmon
------------------------------
To use *Modmobmap* with XGold modems, the use of xgoldmon will be required. But for now, only the fork for *Modmobmap* works to retrieve exact information of cells via the DIAG interface, and could be downloaded in with the following URL: https://github.com/FlUxIuS/xgoldmon
Then after compiling, the tool *xgoldmon* could be started using the *-m* parameter like this:
```
sudo ./xgoldmon -t s3 -m /dev/ttyACM1
```
This will create a FIFO file that will be requested by Modmobmap later:
```
$ ls
celllog.fifo Makefile screenshot-mtsms-while-in-a-call.png xgoldmon
```
Then we can start running *Modmobmap* as follows precising the AT serial interface (*/dev/ttyACM0*) and the fifo file created by *xgoldmon* (*<xgoldmonpath/celllog.fifo*):
```
$ sudo python3 modmobmap.py -f /<xgoldmon path>/celllog.fifo -m xgoldmod -a /dev/ttyACM0 -o
=> Requesting a list of MCC/MNC. Please wait, it may take a while...
Found 4 operators in cache, you choose to reuse them.
Found 4 operator(s)
{'20801': 'Orange', '20810': 'F SFR', '20815': 'Free', '20820': 'F-Bouygues Telecom'}
[+] New cell detected [CellID/PCI-DL_freq (0x7XXXX-65535)]
Network type=3G
PLMN=208-1
Downlink UARFCN=65535
Uplink UARFCN=2850
[+] Unregistered from current PLMN
[+] New cell detected [CellID/PCI-DL_freq (0x7XXXX-3011)]
Network type=3G
PLMN=208-1
Downlink UARFCN=3011
Uplink UARFCN=2786
[...]
[+] Unregistered from current PLMN
=> Changing MCC/MNC for: 20810
[+] New cell detected [CellID/PCI-DL_freq (0x3XXXXX-3075)]
Network type=3G
PLMN=208-10
Downlink UARFCN=3075
Uplink UARFCN=2850
[...]
```
Note: Some trouble could be expected when retrieving results from AT+COPS command. The best way is to use targeted or operators in cache.
Saving results
---------------
The process could be stopped any time and results are save when killing the process with a keyboard interrupt signal:
```
[...]
^C[+] Cells save as cells_1528738901.json
```

0
__init__.py Normal file
View File

6
cache/operators.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"20801": "Orange F",
"20810": "F SFR",
"20815": "Free",
"20820": "F-Bouygues Telecom"
}

8
core/__init__.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

28
core/mKB.py Normal file
View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
class _Singleton(type):
""" A metaclass that creates a Singleton base class when called. """
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(_Singleton('SingletonMeta', (object,), {})): pass
class mKB(Singleton):
config = {
'verbose' : True,
'output' : None,
}
data = {}
def output2xml(string):
init = None

44
core/mLog.py Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
from core.mKB import *
from utils.colors import bcolors
def Cellslogger(func):
def wrapped(*args, **kwargs):
result = func(*args, **kwargs)
kb = mKB()
if 'SM_cells' not in kb.data:
kb.data['SM_cells'] = {}
id_ = v = None
try:
id_,v = list(result.items())[0]
except:
pass
#print ("Error Celllog: %s" % result)
if id_ not in kb.data['SM_cells'] and id_ is not None:
kb.data['SM_cells'][id_] = v
if kb.config['verbose'] == True:
string2print = "[+] New cell detected [CellID/PCI-DL_freq (%s)]" % id_
string2print += "\n\r Network type=%s" % v['type']
string2print += "\n\r PLMN=%s" % v['PLMN']
if 'band' in v:
string2print += "\n\r Band=%i" % v['band']
if '4G' in v['type']:
string2print += "\n\r Downlink EARFCN=%i" % v['eARFCN']
elif '3G' in v['type']:
string2print += "\n\r Downlink UARFCN=%i" % v['RX']
string2print += "\n\r Uplink UARFCN=%i" % v['TX']
elif '2G' in v['type']:
string2print += "\n\r ARFCN=%i" % v['arfcn']
print (bcolors.OKGREEN+string2print+bcolors.ENDC)
return result
return wrapped

8
engines/__init__.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

View File

@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
import subprocess
import threading
import os.path
import sys
import re
if sys.version_info >= (3,0):
from queue import Queue
else:
from Queue import Queue
default_android_sdk_path = "/opt/android/android-sdk-linux"
class ADBError(Exception):
def __init__(self, value):
if value == 'platform':
self.value = "The plateform is not supported for the moment."
elif value == 'dev':
self.value = "libRIL use an unsupported argument."
else:
self.value = "Unknown error: " + value
def __str__(self):
return repr(self.value)
class AsynchronousFileReader(threading.Thread):
'''
ref: http://stefaanlippens.net/python-asynchronous-subprocess-pipe-reading/
Helper class to implement asynchronous reading of a file
in a separate thread. Pushes read lines on a queue to
be consumed in another thread.
'''
def __init__(self, fd, queue):
assert isinstance(queue, Queue)
assert callable(fd.readline)
threading.Thread.__init__(self)
self._fd = fd
self._queue = queue
self._stop = threading.Event()
def run(self):
'''The body of the tread: read lines and put them on the queue.'''
for line in iter(self._fd.readline, ''):
self._queue.put(line)
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
def eof(self):
'''Check whether there is no more content to expect.'''
return not self.is_alive() and self._queue.empty()
class ADBshell(object):
androidsdkpath = None
def __init__(self, androidsdkpath=None):
self.androidsdkpath = androidsdkpath
def _buildcommand(self, command):
adbpath = None
if self.androidsdkpath is not None:
if 'linux' in sys.platform.lower():
adbpath = self.androidsdkpath + '/platform-tools/adb'
if adbpath is None:
raise ADBError('platform')
commandstring = [adbpath, 'shell']
commandstring.extend(command.split(' '))
return commandstring
def run_adbcmdshell(self, command):
commandstring = self._buildcommand(command)
return subprocess.Popen(commandstring, stdout=subprocess.PIPE)
def getDevfile(self):
'''
Get RILd devicename
out: string devicename
'''
process = self.run_adbcmdshell('getprop rild.libargs')
devfile = process.stdout.readline().split(b'/dev/')
if len(devfile) >= 2:
m = re.match(b'([\d\w]+)', devfile[1])
if m is not None:
devfile = b'/dev/' + devfile[1].replace(b'\r\n', b'')
else:
raise ADBError('bad dev string')
else:
raise ADBError('dev')
return devfile.decode("utf-8")
def _parseCOPS(self, string):
'''
Parse AT+COPS=? information
in(1): string cops returned string
out: dict infos
'''
dict_ = {}
rstr = string.replace(b'+COPS: ', b'')
for x in rstr.split(b'),'):
ysp = x.split(b',')
if len(ysp) == 5:
mccmnc = ysp[3].decode("utf-8").replace('"','')
netname = ysp[1].decode("utf-8").replace('"','')
if mccmnc not in dict_:
dict_[mccmnc] = netname
return dict_
def getCOPSfromRIL(self):
'''
Grab PLMN information
return: dict PLMN infos
'''
devfile = self.getDevfile()
process = self.run_adbcmdshell("su -c 'echo -e \"AT\r\n\" > %s'" % devfile)
process = self.run_adbcmdshell("su -c 'echo -e \"AT+COPS=?\r\n\" > %s && cat %s'" % (devfile,devfile))
#process = self.run_adbcmdshell("su -c 'cat %s'" % devfile)
stdout_queue = Queue()
stdout_reader = AsynchronousFileReader(process.stdout, stdout_queue)
stdout_reader.daemon=True
stdout_reader.start()
stop = False
copsList = None
countBL = 0
while not stdout_reader.eof() and stop is False:
while not stdout_queue.empty() and stop is False:
try:
line = stdout_queue.get()
if b'+COPS: ' in line:
copsList = self._parseCOPS(line)
if len(copsList) > 0:
stop = True
stdout_reader.stop()
process = None
return copsList
else:
if len(line) == 0:
countBL += 1
if countBL == 10:
stop = True
except KeyboardInterrupt:
stop = True
stdout_reader.stop()
process.stdout.close()
return copsList
def changePLMN(self, MCCMNC, automode=False):
'''
Change PLMN using AT commands
in(1): string MCCMNC
in(2): Bool automode
out: process resurl
'''
mode = 1
devfile = self.getDevfile()
if automode is True:
mode = 0
process = self.run_adbcmdshell("su -c 'echo -e \"AT+COPS=%i,2,%s\r\n\" > %s'" % (mode, MCCMNC, devfile))
return process
def changeNetworkTypeGBox(self, type_=1):
'''
Change Networktype mode using GravityBox
in(1): int Networktype mode.
out: process result
'''
process = self.run_adbcmdshell("su -c 'am broadcast -a gravitybox.intent.action.CHANGE_NETWORK_TYPE --ez networkType %i'" % type_)
return process
def changeNetworkType(self, type_=2):
'''
Change Networktype mode using AT commands
in(1): int Networktype mode.
2 for Autoselect, 13 for GSM only and 14 for 3G only.
out: process result
'''
devfile = self.getDevfile()
process = self.run_adbcmdshell("su -c 'echo -e \"AT^SYSCONFIG=%i,1,1,2\r\n\" > %s'" % (type_, devfile))
return process
def deregister(self):
'''
Unregister UE from current PLMN
out: process result
'''
devfile = self.getDevfile()
process = self.run_adbcmdshell("su -c 'echo -e \"AT+COPS=2\r\n\" > %s'" % devfile)
return process
def airplanemode(self, mode=0):
'''
UE airplane mode switch
in(1): int mode - 1 = ON, 0 = OFF
out: process result
'''
self.run_adbcmdshell("su -c 'settings put global airplane_mode_on %i'" % int(mode))
process = self.run_adbcmdshell("su -c 'am broadcast -a android.intent.action.AIRPLANE_MODE'")
return process
def pushsecretcode(self, secretcode):
'''
Call Android secret codes
in(1): String secretcode to call
out: process result
'''
process = self.run_adbcmdshell("su -c 'am broadcast -a android.provider.Telephony.SECRET_CODE -d android_secret_code://%s'" % secretcode)
return process

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
class RILd(object):
androidsdkpath = None
def __init__(self, androidsdkpath=None):
self.androidsdkpath = androidsdkpath

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

View File

@ -0,0 +1,213 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
from engines.android.generic.ADBshell import *
from core.mKB import *
from core.mLog import *
from utils.colors import *
class ServiceMode(ADBshell):
'''
Class abstracting abstracting action to get mobile cells information from ServiceMode
'''
@Cellslogger
def parse4Gcell(self, string):
'''
Parse 4G cells information
in(1): string returned by logcat
out: dict infos
'''
plmn = None
tac = None
earfcn = None
band = None
bandwidth = None
pci = None
cell = {}
for s in string.split(b'\r\n'):
if b'LTE' in s:
if b'Band' in s:
band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
elif b'BAND' in s and b'BW' in s:
band, bandwidth = re.match(b'^.*BAND:?\s?(\d+)\sBW:?\s?([\d+\w]+)?\s?\_$', s).groups()
if b'MCC-MNC' in s:
if b'TAC' in s:
plmn, tac = re.match(b'^.*MCC-MNC?\s?:?\s?([\d\-]+)\,?\s?TAC:?\s?(\d+)?\s?\_$', s).groups()
elif b'MeG':
plmn = re.match(b'^.*MCC-MNC?\s?:?\s?([\d\-\s]+)', s).group(1)
if b'Earfcn_dl:' in s:
earfcn, pci = re.match(b'^.*Earfcn_dl:?\s?(\d+),?\s?PCI:?\s?(\d+)?\s?\_', s).groups()
if b'LTE DL BW' in s:
bandwidth = re.match(b'^.*BW?\s?:?\s?([\d\w]+)', s).group(1)
if tac is None and b'TAC' in s:
tac = re.match(b'^.*TAC?\s?:?\s?([\d]+)', s).group(1)
if None not in [plmn, tac, earfcn, band, bandwidth, pci]:
tac = tac.decode('utf-8')
plmn = plmn.decode('utf-8').replace(' ','')
pci = pci.decode('utf-8')
bandwidth = bandwidth.decode('utf-8')
cid2 = "%s-%i" % (pci, int(earfcn))
cell[cid2] = { 'PLMN' : plmn,
'band' : int(band),
'bandwidth' : bandwidth,
'eARFCN': int(earfcn),
'PCI' : pci,
'TAC' : tac,
'type' : '4G',
}
return cell
@Cellslogger
def parse3Gcell_sgs3like(self, string):
'''
Parse 3G cells information
in(1): string returned by logcat
out: dict infos
'''
plmn = None
cid = None
tx = None
rx = None
band = None
cell = {}
for s in string.split(b'\r\n'):
if b'Band' in s:
band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
if b'Reg PLMN' in s:
plmn = re.match(b'^.*Reg PLMN?\s?([\d\-]+)', s).group(1)
if b'CELL_ID' in s:
cid = re.match(b'^.*CELL_ID:?\s?(\S+)', s).group(1)
if b'CH DL:' in s:
tx = re.match(b'^.*CH DL:?\s?(\d+)', s).group(1)
if b', UL:' in s:
rx = re.match(b'^.*\,\sUL:?\s?(\d+)', s).group(1)
if None not in [tx, rx, cid, plmn, band]:
cid = cid.decode('utf-8').replace('_','')
plmn = plmn.decode("utf-8").replace(' ', '')
cid2 = "%s-%i" % (cid, int(rx))
cell[cid2] = { 'PLMN' : plmn,
'TX' : int(tx),
'RX' : int(rx),
'band': int(band),
'type' : '3G',
}
return cell
@Cellslogger
def parse3Gcell(self, string):
'''
Parse 3G cells information SGS3 like structs
in(1): string returned by logcat
out: dict infos
'''
plmn = None
cid = None
tx = None
rx = None
band = None
cell = {}
for s in string.split(b'\r\n'):
if b'Band' in s:
band = re.match(b'^.*Band?:?\s?(\d+)', s).group(1)
if b'PLMN:' in s:
plmn = re.match(b'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
elif b'MCC-MNC :' in s:
plmn = re.match(b'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
if b'CID:' in s:
cid = re.match(b'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
if b' TX:' in s:
tx = re.match(b'^.*TX:?\s?(\d+)', s).group(1)
if b' RX:' in s:
rx = re.match(b'^.*RX:?\s?(\d+)', s).group(1)
if None not in [tx, rx, cid, plmn, band]:
cid = cid.decode('utf-8')
plmn = plmn.decode("utf-8").replace(' ', '')
cid2 = "%s-%i" % (cid, int(rx))
cell[cid2] = { 'PLMN' : plmn,
'TX' : int(tx),
'RX' : int(rx),
'band': int(band),
'type' : '3G',
}
return cell
@Cellslogger
def parse2Gcell(self, string):
'''
Parse 2G cells information SGS5 like structs
in(1): string returned by logcat
out: dict infos
'''
plmn = None
cid = None
arfcn = None
cell = {}
for s in string.split(b'\r\n'):
if b'PLMN:' in s:
plmn = re.match(b'^.*PLMN:?\s?([\d\-]+)?\s?\_$', s).group(1)
elif b'MCC-MNC :' in s:
plmn = re.match(b'^.*MCC-MNC\s:?\s?([\d\-\s]+)?\s?\_$', s).group(1)
if b'CID:' in s:
cid = re.match(b'^.*CID:?\s?(\S+)?\s?_$', s).group(1)
if b' Tra:' in s:
arfcn = re.match(b'^.*Tra:?\s?(\d+)', s).group(1)
if None not in [arfcn, cid, plmn]:
cid = cid.decode('utf-8')
plmn = plmn.decode("utf-8").replace(' ', '')
cid2 = "%s-%i" % (cid, int(arfcn))
cell[cid2] = { 'PLMN' : plmn,
'arfcn' : int(arfcn),
'type' : '2G',
'cid' : cid,
}
return cell
def grablogcat(self):
'''
Grab ServiceMode information from logcat
out: dict ParsedCell
'''
process = self.run_adbcmdshell('logcat -s ServiceModeApp_RIL:I,ServiceMode:I,ModemServiceMode:I')
stdout_queue = Queue()
stdout_reader = AsynchronousFileReader(process.stdout, stdout_queue)
stdout_reader.daemon=True
stdout_reader.start()
stop = False
capture = b''
while not stdout_reader.eof() and stop is False:
while not stdout_queue.empty() and stop is False:
try:
line = stdout_queue.get()
if b'Update!' in line:
if b'LTE RRC:' in capture:
self.parse4Gcell(capture)
elif b'UMTS :' in capture:
self.parse3Gcell_sgs3like(capture)
if b'GSM' in capture:
self.parse2Gcell(capture)
else:
self.parse3Gcell(capture)
capture = b''
capture += line
except (KeyboardInterrupt, SystemExit):
stop = True
stdout_reader.stop()
stdout_reader.stop()
process.stdout.close()
def output2xml():
from xml.dom.minidom import Document
kb = mKB()
root = doc.createElement('moncells')
for k,v in kb.data['SM_cells'].items():
cell = doc.createElement('cell')
root.appendChild(cell)

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

8
engines/host/__init__.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
from core.mLog import Cellslogger
from core.mKB import *
class xgoldmod(object):
@Cellslogger
def go2logs(self, cell):
return cell
def parseFifo(self):
kb = mKB()
FIFO = kb.config['file']
if 'SM_cells' not in kb.data:
kb.data['SM_cells'] = {}
while True:
with open(FIFO) as fifo:
while True:
data = fifo.read()
if len(data) == 0:
break
infos = data.split(':')[1]
isplit = infos.split(';')
tmpcell = {}
tmpcell2 = {}
for cell in isplit:
pcell = cell.split('=')
tmpcell[pcell[0]] = pcell[1]
cid = tmpcell['CID'] + '-' + tmpcell['DL_UARFCN']
tmpcell2[cid] = { 'PLMN' : tmpcell['PLMN'],
'RAC' : tmpcell['RAC'],
'LAC' : tmpcell['LAC'],
'type' : '3G',
'RX' : int(tmpcell['DL_UARFCN']),
'TX' : int(tmpcell['UL_UARFCN'].split('\0')[0]),
}
self.go2logs(tmpcell2)

59
engines/host/serial/AT.py Normal file
View File

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
import serial
class AT(object):
tty_int = None
def __init__(self, tty_path):
self.tty_int = serial.Serial(tty_path, 115200)
def _parseCOPS(self, string):
'''
Parse AT+COPS=? information
in(1): string cops returned string
out: dict infos
'''
dict_ = {}
rstr = string.replace(b'+COPS: ', b'')
for x in rstr.split(b'),'):
ysp = x.split(b',')
if len(ysp) >= 5:
mccmnc = ysp[3].decode("utf-8").replace('"','')
netname = ysp[1].decode("utf-8").replace('"','')
if mccmnc not in dict_:
dict_[mccmnc] = netname
return dict_
def getCOPS(self):
tty_int = self.tty_int
tty_int.write(b'AT+COPS=?\r\n')
tty_int.readline() # command sent
result = tty_int.readline()
#tty_int.readline()
return self._parseCOPS(result)
def changePLMN(self, MCCMNC, automode=False):
mode = 1
tty_int = self.tty_int
if automode is True:
mode = 0
tty_int.write(b"AT+COPS=%i,2,\"%s\"\r\n" % (mode, MCCMNC.encode('utf-8')))
def unregister(self):
tty_int = self.tty_int
tty_int.write(b"AT+COPS=2\r\n")
def changeNetworkType(self, type_=2):
'''
Change Networktype mode using AT commands
in(1): int Networktype mode.
2 for Autoselect, 13 for GSM only and 14 for 3G only.
out: process result
'''
tty_int = self.tty_int
tty_int.write(b"AT^SYSCONFIG=%i,1,1,2\r\n")
if __name__ == "__main__":
ser = AT('/dev/ttyACM0')
print (ser.getCOPS())
ser.changePLMN(b'20801')

View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

67
modmobmap.py Executable file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
from utils.logprocess import *
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Mobile network mapping tool with cheap equipments')
parser.add_argument('-m', '--module', dest='module', required=False, default='servicemode',
help='Module to use (e.g: "servicemode" by default)')
parser.add_argument('-n', '--networks', dest='networks', required=False, default=None,
help='Networks in MCCMNC format splitted with commas')
parser.add_argument('-o', '--cached_operator', dest='operators', required=False, default=False, action='store_true',
help='Use operator in cache to speed up the passive scan')
parser.add_argument('-s', '--sdk', dest='androidsdk', required=False, default='/opt/Android',
help='Android SDK path')
parser.add_argument('-a', '--at', dest='atmode', required=False, default=None,
help='AT access mode. If host put something like "/dev/ttyUSBxx. By default it uses ADB."')
parser.add_argument('-f', '--file', dest='file', required=False, default=None,
help='File to parse. For the moment it could be used in combination with AT mode host.')
args = parser.parse_args()
sm = ADBshell()
kb = mKB()
kb.config['androidsdk'] = args.androidsdk
sm.androidsdkpath = args.androidsdk
if args.file is not None:
kb.config['file'] = args.file
if args.module == "xgoldmod":
startXgoldmodCollect()
else:
startServiceModeCollect()
cops = None
if args.networks is not None:
printInfo('=> Manual MCC/MNC processing...')
cops = processManualMCCMN(args.networks)
else:
printInfo('=> Requesting a list of MCC/MNC. Please wait, it may take a while...')
operators = load_operators()
if args.operators is True:
print (bcolors.WARNING+"Found %i operators in cache, you choose to reuse them." % len(operators) + bcolors.ENDC)
cops = operators
if cops is None:
if args.atmode is None:
cops = sm.getCOPSfromRIL()
else:
at = AT(args.atmode)
cops = at.getCOPS()
saveMCCMNC(cops)
if cops is None:
sys.exit("Problem with AT+COPS=? anwser. Please reboot the phone and try again")
else:
print (bcolors.WARNING+"Found %i operator(s)" % len(cops))
print (cops, bcolors.ENDC)
operators = [x for x,y in cops.items()]
if args.atmode is None:
processOperatorADB(operators)
else:
kb.config['tty_file'] = args.atmode
processOperatorAT(operators)

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
serial

8
utils/__init__.py Normal file
View File

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------

16
utils/colors.py Normal file
View File

@ -0,0 +1,16 @@
# temp colors taken from some stackoverflow post I guess
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
def disable(self):
self.HEADER = ''
self.OKBLUE = ''
self.OKGREEN = ''
self.WARNING = ''
self.FAIL = ''
self.ENDC = ''

486
utils/eu_arfcn_calc.py Executable file
View File

@ -0,0 +1,486 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
# ----------------------------------------------------------------------------
from __future__ import print_function
#####################################
# UARFCN and EARFCN Calculator
#####################################
##
# Tables
#
table_earfcn = {
1 : { 'FDL_Low' : 2110,
'NDL_Offset' : 0,
'DL_range' : (0,599),
'FUL_Low' : 1920,
'NUL_Offset' : 18000,
'UP_range' : (1800,18599),
},
2 : { 'FDL_Low' : 1930,
'NDL_Offset' : 600,
'DL_range' : (600,1199),
'FUL_Low' : 1850,
'NUL_Offset' : 18600,
'UP_range' : (18600,19199),
},
3 : { 'FDL_Low' : 1805,
'NDL_Offset' : 1200,
'DL_range' : (1200,1949),
'FUL_Low' : 1710,
'NUL_Offset' : 19200,
'UP_range' : (19200,19949),
},
4 : { 'FDL_Low' : 2110,
'NDL_Offset' : 1950,
'DL_range' : (1950,2399),
'FUL_Low' : 1710,
'NUL_Offset' : 19950,
'UP_range' : (19950,20399),
},
5 : { 'FDL_Low' : 869,
'NDL_Offset' : 2400,
'DL_range' : (2400,2649),
'FUL_Low' : 824,
'NUL_Offset' : 20400,
'UP_range' : (20400,20649),
},
6 : { 'FDL_Low' : 875,
'NDL_Offset' : 2650,
'DL_range' : (2650,2749),
'FUL_Low' : 830,
'NUL_Offset' : 20650,
'UP_range' : (20650,20749),
},
7 : { 'FDL_Low' : 2620,
'NDL_Offset' : 2750,
'DL_range' : (2750,3449),
'FUL_Low' : 2500,
'NUL_Offset' : 20750,
'UP_range' : (20750,21449),
},
8 : { 'FDL_Low' : 925,
'NDL_Offset' : 3450,
'DL_range' : (3450,3799),
'FUL_Low' : 880,
'NUL_Offset' : 21450,
'UP_range' : (21450,21799),
},
9 : { 'FDL_Low' : 1844.9,
'NDL_Offset' : 3800,
'DL_range' : (3800,4149),
'FUL_Low' : 1749.9,
'NUL_Offset' : 21800,
'UP_range' : (21800,22149),
},
10 : { 'FDL_Low' : 2110,
'NDL_Offset' : 4150,
'DL_range' : (4150,4749),
'FUL_Low' : 1710,
'NUL_Offset' : 22150,
'UP_range' : (22150,22749),
},
11 : { 'FDL_Low' : 1475.9,
'NDL_Offset' : 4750,
'DL_range' : (4750,4949),
'FUL_Low' : 1427.9,
'NUL_Offset' : 22750,
'UP_range' : (22750,22949),
},
12 : { 'FDL_Low' : 729,
'NDL_Offset' : 5010,
'DL_range' : (5010,5179),
'FUL_Low' : 699,
'NUL_Offset' : 23010,
'UP_range' : (23010,23179),
},
13 : { 'FDL_Low' : 746,
'NDL_Offset' : 5180,
'DL_range' : (5180,5279),
'FUL_Low' : 777,
'NUL_Offset' : 23180,
'UP_range' : (23180,23279),
},
14 : { 'FDL_Low' : 758,
'NDL_Offset' : 5280,
'DL_range' : (5280,5379),
'FUL_Low' : 788,
'NUL_Offset' : 23280,
'UP_range' : (23280,23379),
},
17 : { 'FDL_Low' : 734,
'NDL_Offset' : 5730,
'DL_range' : (5730,5849),
'FUL_Low' : 704,
'NUL_Offset' : 23730,
'UP_range' : (23730,23849),
},
18 : { 'FDL_Low' : 860,
'NDL_Offset' : 5850,
'DL_range' : (5850,5999),
'FUL_Low' : 815,
'NUL_Offset' : 23850,
'UP_range' : (23850,23999),
},
19 : { 'FDL_Low' : 875,
'NDL_Offset' : 6000,
'DL_range' : (6000,6149),
'FUL_Low' : 830,
'NUL_Offset' : 24000,
'UP_range' : (24000,24149),
},
20 : { 'FDL_Low' : 791,
'NDL_Offset' : 6150,
'DL_range' : (6150,6449),
'FUL_Low' : 832,
'NUL_Offset' : 24150,
'UP_range' : (24150,24449),
},
21 : { 'FDL_Low' : 1495.9,
'NDL_Offset' : 6450,
'DL_range' : (6450,6599),
'FUL_Low' : 1447.9,
'NUL_Offset' : 24450,
'UP_range' : (24450,24599),
},
22 : { 'FDL_Low' : 3510,
'NDL_Offset' : 6600,
'DL_range' : (6600,7399),
'FUL_Low' : 3410,
'NUL_Offset' : 24600,
'UP_range' : (24600,25399),
},
23 : { 'FDL_Low' : 2180,
'NDL_Offset' : 7500,
'DL_range' : (7500,7699),
'FUL_Low' : 2000,
'NUL_Offset' : 25500,
'UP_range' : (25500,25699),
},
24 : { 'FDL_Low' : 1525,
'NDL_Offset' : 7700,
'DL_range' : (7700,8039),
'FUL_Low' : 1626.5,
'NUL_Offset' : 25700,
'UP_range' : (25700,26039),
},
25 : { 'FDL_Low' : 1930,
'NDL_Offset' : 8040,
'DL_range' : (8040,8689),
'FUL_Low' : 1850,
'NUL_Offset' : 26040,
'UP_range' : (26040,26689),
},
26 : { 'FDL_Low' : 859,
'NDL_Offset' : 8690,
'DL_range' : (8690,9039),
'FUL_Low' : 814,
'NUL_Offset' : 26690,
'UP_range' : (26690,27039),
},
27 : { 'FDL_Low' : 852,
'NDL_Offset' : 9040,
'DL_range' : (9040,9209),
'FUL_Low' : 807,
'NUL_Offset' : 27040,
'UP_range' : (27040,27209),
},
28 : { 'FDL_Low' : 758,
'NDL_Offset' : 9210,
'DL_range' : (9210,9659),
'FUL_Low' : 703,
'NUL_Offset' : 27210,
'UP_range' : (27210,27659),
},
30 : { 'FDL_Low' : 2350,
'NDL_Offset' : 9770,
'DL_range' : (9770,9869),
'FUL_Low' : 2305,
'NUL_Offset' : 27660,
'UP_range' : (27660,27759),
},
31 : { 'FDL_Low' : 462.5,
'NDL_Offset' : 9870,
'DL_range' : (9870,9919),
'FUL_Low' : 452.5,
'NUL_Offset' : 27760,
'UP_range' : (27760,27809),
},
65 : { 'FDL_Low' : 2110,
'NDL_Offset' : 65536,
'DL_range' : (65536,66435),
'FUL_Low' : 1920,
'NUL_Offset' : 131072,
'UP_range' : (131072,131971),
},
66 : { 'FDL_Low' : 2110,
'NDL_Offset' : 66436,
'DL_range' : (66436,67335),
'FUL_Low' : 1710,
'NUL_Offset' : 131972,
'UP_range' : (131972,132671),
},
68 : { 'FDL_Low' : 753,
'NDL_Offset' : 67536,
'DL_range' : (67536,67835),
'FUL_Low' : 698,
'NUL_Offset' : 132672,
'UP_range' : (132672,132971),
},
70 : { 'FDL_Low' : 1995,
'NDL_Offset' : 68336,
'DL_range' : (68336,68585),
'FUL_Low' : 1695,
'NUL_Offset' : 132972,
'UP_range' : (132972,133121),
},
71 : { 'FDL_Low' : 617,
'NDL_Offset' : 68586,
'DL_range' : (68586,68935),
'FUL_Low' : 663,
'NUL_Offset' : 133122,
'UP_range' : (133122,133471),
},
72 : { 'FDL_Low' : 461,
'NDL_Offset' : 68936,
'DL_range' : (68936,68985),
'FUL_Low' : 451,
'NUL_Offset' : 133472,
'UP_range' : (133472,133521),
},
73 : { 'FDL_Low' : 460,
'NDL_Offset' : 68986,
'DL_range' : (68986,69465),
'FUL_Low' : 450,
'NUL_Offset' : 133522,
'UP_range' : (133522,133571),
},
74 : { 'FDL_Low' : 1475,
'NDL_Offset' : 69036,
'DL_range' : (69036,69035),
'FUL_Low' : 1427,
'NUL_Offset' : 133572,
'UP_range' : (133572,134001),
},
85 : { 'FDL_Low' : 728,
'NDL_Offset' : 70366,
'DL_range' : (70366,70545),
'FUL_Low' : 698,
'NUL_Offset' : 134002,
'UP_range' : (134002,134181),
},
}
table_uarfcn = {
1 : { 'FDL_Offset' : 0,
'FDL_Low' : 2112.4,
'DL_range' : (10562,10838),
'FUL_Low' : 1922.4,
'NUL_Offset' : 0,
'UP_range' : (9612,9888),
},
2 : { 'FDL_Offset' : 0,
'FDL_Low' : 1932.4,
'DL_range' : (9662,9938),
'FUL_Low' : 1852.4,
'NUL_Offset' : 0,
'UP_range' : (9262,9538),
},
3 : { 'FDL_Offset' : 1525,
'FDL_Low' : 1712.4,
'DL_range' : (937,1288),
'FUL_Low' : 1807.4,
'NUL_Offset' : 1575,
'UP_range' : (1162,1513),
},
4 : { 'FDL_Offset' : 1805,
'FDL_Low' : 2112.4,
'DL_range' : (1537,1738),
'FUL_Low' : 1712.4,
'NUL_Offset' : 1450,
'UP_range' : (1312,1513),
},
5 : { 'FDL_Offset' : 0,
'FDL_Low' : 871.4,
'DL_range' : (4357,4458),
'FUL_Low' : 826.4,
'NUL_Offset' : 0,
'UP_range' : (4132,4233),
},
6 : { 'FDL_Offset' : 0,
'FDL_Low' : 877.4,
'DL_range' : (4387,4413),
'FUL_Low' : 832.4,
'NUL_Offset' : 0,
'UP_range' : (4162,4188),
},
7 : { 'FDL_Offset' : 2175,
'FDL_Low' : 2622.4,
'DL_range' : (2237,2563),
'FUL_Low' : 2502.4,
'NUL_Offset' : 2100,
'UP_range' : (2012,2338),
},
8 : { 'FDL_Offset' : 340,
'FDL_Low' : 927.4,
'DL_range' : (2937,3088),
'FUL_Low' : 882.4,
'NUL_Offset' : 340,
'UP_range' : (2712,2863),
},
9 : { 'FDL_Offset' : 0,
'FDL_Low' : 1847.4,
'DL_range' : (9237,93878),
'FUL_Low' : 1752.4,
'NUL_Offset' : 0,
'UP_range' : (8762,8912),
},
10 : { 'FDL_Offset' : 1490,
'FDL_Low' : 2112.4,
'DL_range' : (3112,3388),
'FUL_Low' : 1712.4,
'NUL_Offset' : 1135,
'UP_range' : (2887,3163),
},
11 : { 'FDL_Offset' : 736,
'FDL_Low' : 1478.4,
'DL_range' : (3712,3812),
'FUL_Low' : 1430.4,
'NUL_Offset' : 733,
'UP_range' : (3487,3587),
},
12 : { 'FDL_Offset' : -37,
'FDL_Low' : 730.4,
'DL_range' : (3837,3903),
'FUL_Low' : 700.4,
'NUL_Offset' : -22,
'UP_range' : (3612,3678),
},
13 : { 'FDL_Offset' : -55,
'FDL_Low' : 748.4,
'DL_range' : (4017,4043),
'FUL_Low' : 779.4,
'NUL_Offset' : 21,
'UP_range' : (3792,3818),
},
14 : { 'FDL_Offset' : -63,
'FDL_Low' : 760.4,
'DL_range' : (4117,4143),
'FUL_Low' : 790.4,
'NUL_Offset' : 12,
'UP_range' : (3892,3918),
},
19 : { 'FDL_Offset' : 735,
'FDL_Low' : 877.4,
'DL_range' : (712,763),
'FUL_Low' : 832.4,
'NUL_Offset' : 770,
'UP_range' : (312,363),
},
20 : { 'FDL_Offset' : -109,
'FDL_Low' : 793.4,
'DL_range' : (4512,4638),
'FUL_Low' : 834.4,
'NUL_Offset' : -23,
'UP_range' : (4287,4413),
},
21 : { 'FDL_Offset' : 1326,
'FDL_Low' : 1498.4,
'DL_range' : (862,912),
'FUL_Low' : 1450.4,
'NUL_Offset' : 1358,
'UP_range' : (462,512),
},
22 : { 'FDL_Offset' : 2580,
'FDL_Low' : 3512.4,
'DL_range' : (4662,5038),
'FUL_Low' : 3412.4,
'NUL_Offset' : 2525,
'UP_range' : (4437,4813),
},
25 : { 'FDL_Offset' : 910,
'FDL_Low' : 1932.4,
'DL_range' : (5112,5413),
'FUL_Low' : 1852.4,
'NUL_Offset' : 875,
'UP_range' : (4887,5188),
},
26 : { 'FDL_Offset' : -291,
'FDL_Low' : 1932.4,
'DL_range' : (5762,5913),
'FUL_Low' : 1852.4,
'NUL_Offset' : -291,
'UP_range' : (5537,5688),
},
}
##
# Functions
#
def uarfcn2freq(band, dl_uarfcn=None, ul_uarfcn=None):
'''
in(1): int band index,
in(2): int Downling UARFCN index,
in(3): int Uplink UARFCN index,
out: tuple (float downlink_freq, float uplink_freq)
'''
duplex_spacing = abs(table_uarfcn[band]['FDL_Low']-table_uarfcn[band]['FUL_Low'])
FDL_Offset = table_uarfcn[band]['FDL_Offset']
FUL_Offset = table_uarfcn[band]['NUL_Offset']
downlink_freq = uplink_freq = None
if dl_uarfcn is not None:
downlink_freq = FDL_Offset + 0.2 * dl_uarfcn
if ul_uarfcn is not None:
uplink_freq = FUL_Offset + 0.2 * ul_uarfcn
if downlink_freq is not None and uplink_freq is None:
uplink_freq = downlink_freq - duplex_spacing
elif downlink_freq is None and uplink_freq is not None:
downlink_freq = downlink_freq + duplex_spacing
return (downlink_freq, uplink_freq)
def earfcn2freq(band, dl_earfcn=None, ul_earfcn=None):
'''
in(1): int band index,
in(2): int Downling EARFCN index,
in(3): int Uplink EARFCN index,
out: tuple (float downlink_freq, float uplink_freq)
'''
NDL_Offset = table_earfcn[band]['NDL_Offset']
NUL_Offset = table_earfcn[band]['NUL_Offset']
duplex_spacing = abs(table_earfcn[band]['FDL_Low']-table_earfcn[band]['FUL_Low'])
FDL_Low = table_earfcn[band]['FDL_Low']
FUL_Low = table_earfcn[band]['FUL_Low']
downlink_freq = uplink_freq = None
if dl_earfcn is not None:
downlink_freq = FDL_Low + 0.1 * (dl_earfcn-NDL_Offset)
if ul_earfcn is not None:
uplink_freq = FUL_Low + 0.1 * (ul_earfcn-NUL_Offset)
if downlink_freq is not None and uplink_freq is None:
uplink_freq = downlink_freq - duplex_spacing
elif downlink_freq is None and uplink_freq is not None:
downlink_freq = downlink_freq + duplex_spacing
return (downlink_freq, uplink_freq)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("nettype", type=int, help="select network type: 1 for 3G, and 2 for 4G")
parser.add_argument("band", type=int, help="Band index")
parser.add_argument("downlink", type=int, help="Downlink U/E-ARFCN")
parser.add_argument("--uplink", type=int, help="Uplink U/E-ARFCN")
args = parser.parse_args()
if args.nettype == 1:
ret = uarfcn2freq(args.band, args.downlink, args.uplink)
elif args.nettype == 2:
ret = earfcn2freq(args.band, args.downlink, args.uplink)
print ("[+] Selected Downlink ARFCN %i (band %i)" % (args.downlink, args.band))
print ("Downlink: %f MHz and Uplink: %f MHz" % (ret[0],ret[1]))

142
utils/logprocess.py Normal file
View File

@ -0,0 +1,142 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <sebastien.dudek(<@T>)synacktiv.com> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return FlUxIuS ;)
from __future__ import print_function
from engines.android.generic.ADBshell import *
from engines.android.samsung.ServiceMode import *
from engines.host.diag.xgoldmod import *
from engines.host.serial.AT import AT
from utils.colors import *
from core.mKB import *
import time
from threading import Thread
import argparse
import json
kb = mKB()
def statesmv(func, msg=None, wait=10, arg=None):
if msg is not None:
print (bcolors.OKBLUE+msg+bcolors.ENDC)
if arg is not None:
func(arg)
else:
func()
time.sleep(wait)
def bringTestMode():
sm = ADBshell()
sm.androidsdkpath = mKB.config['androidsdk']
statesmv(sm.pushsecretcode, arg='4636', wait=2)
def bringServiceMode():
sm = ADBshell()
sm.androidsdkpath = mKB.config['androidsdk']
statesmv(sm.pushsecretcode, arg='0011', wait=2)
def startXgoldmodCollect():
xg = xgoldmod()
th = Thread(target=xg.parseFifo)
th.daemon = True
th.start()
def startServiceModeCollect():
sm = ServiceMode()
sm.androidsdkpath = mKB.config['androidsdk']
bringTestMode()
bringServiceMode()
th = Thread(target=sm.grablogcat)
th.daemon = True
th.start()
def printInfo(string):
print (bcolors.OKBLUE+string+bcolors.ENDC)
def saveCells(obj):
import time
jscells = json.dumps(obj, indent=4, sort_keys=True)
name = "cells_%d.json" % float(time.time())
f = open("%s" % name, 'w+')
f.write(jscells)
f.close()
printInfo("[+] Cells save as %s" % name)
def processOperatorAT(operators):
at_tty = kb.config['tty_file']
at = AT(at_tty)
state = True
while state:
try:
for code in operators:
statesmv(at.unregister,
"[+] Unregistered from current PLMN")
statesmv(at.changePLMN,
"=> Changing MCC/MNC for: %s" % code, arg=code)
statesmv(at.changeNetworkType,
"=> Changing network type for 3G only", arg=14)
statesmv(at.changeNetworkType,
"=> Changing network type for 2G only", arg=13)
statesmv(at.changeNetworkType,
"=> Switching back to auto-mode", arg=2)
except (KeyboardInterrupt, SystemExit):
state = False
cells = kb.data['SM_cells']
saveCells(cells)
def processOperatorADB(operators):
sm = ADBshell()
sm.androidsdkpath = mKB.config['androidsdk']
state = True
while state:
try:
for code in operators:
statesmv(sm.deregister,
"[+] Unregistered from current PLMN")
statesmv(sm.changePLMN,
"=> Changing MCC/MNC for: %s" % code, arg=code)
statesmv(sm.changeNetworkType,
"=> Changing network type for 3G only", arg=14)
statesmv(sm.changeNetworkType,
"=> Changing network type for 2G only", arg=13)
statesmv(sm.changeNetworkType,
"=> Switching back to auto-mode", arg=2)
except (KeyboardInterrupt, SystemExit):
state = False
kb = mKB()
cells = kb.data['SM_cells']
saveCells(cells)
process = sm.grablogcat()
def processManualMCCMN(string):
dic_ = {}
splitted = string.replace(' ','').split(',')
for code in splitted:
dic_[code] = code
return dic_
def load_operators():
try:
f = open('cache/operators.json', 'r')
operators = json.loads(f.read())
return operators
if len(operators) > 0 or operators is not None:
print (bcolors.WARNING+"Found %i operators in cache, do you want to reuse them?:\n\t%s"+bcolors.ENDC % (len(operators), str(operators)))
answ = input('(Y)es or (N)o?')
if answ.lower() is 'y':
return operators
f.close()
except:
return None
def saveMCCMNC(obj):
jscache = json.dumps(obj, indent=4, sort_keys=True)
f = open('cache/operators.json', 'w+')
f.write(jscache)
f.close()