Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
doronz88 committed Oct 20, 2021
0 parents commit 4a77933
Show file tree
Hide file tree
Showing 9 changed files with 933 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python application

on:
push:
branches: [ '**' ]
pull_request:
branches: [ '**' ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
python-version: [3.7, 3.8, 3.9, "3.10"]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8
pip install -r requirements.txt
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
31 changes: 31 additions & 0 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Upload Python Package

on:
release:
types: [created]

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*.pyc
.idea/
venv/
build/
dist/
*.egg-info/
version.txt
debug/
*.DS_Store
tickets
.idea

674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Description

Simple utility to search for interesting preferences in iDevices.

# Installation

```shell
python3 -m pip install -U --user cfprefsmon
```

# Example

In this example, where the value for each preference is `None`, this is probably some hidden feature we can maybe enable
on a jailbroken device.

```
➜ cfprefmon git:(master) ✗ cfprefsmon
CFPreference[com.apple.springboard][kCFPreferencesAnyUser][SBDisableHomeButton] = 0 # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.springboard][kCFPreferencesAnyUser][SBStoreDemoAppLock] = 0 # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.springboard][kCFPreferencesAnyUser][ThermalLockoutEnabledBrickMode] = 0 # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.backboardd][kCFPreferencesAnyUser][BKForceMirroredOrientation] = None # Process: /usr/libexec/backboardd
CFPreference[com.apple.backboardd][kCFPreferencesAnyUser][BKForceMirroredOrientation] = None # Process: /usr/libexec/backboardd
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][canvas_width] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][canvas_height] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][enable_ktrace] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][override_display_width] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][override_display_height] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][override_panel_width] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][override_panel_height] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.iokit.IOMobileGraphicsFamily][kCFPreferencesAnyUser][benchmark] = None # Process: /System/Library/CoreServices/SpringBoard.app/SpringBoard
CFPreference[com.apple.coreservices.useractivityd][kCFPreferencesAnyUser][ActivityAdvertisingAllowed] = 1 # Process: /System/Library/PrivateFrameworks/UserActivity.framework/Agents/useractivityd
CFPreference[com.apple.coreservices.useractivityd][kCFPreferencesAnyUser][ActivityAdvertisingAllowed] = 1 # Process: /System/Library/PrivateFrameworks/UserActivity.framework/Agents/useractivityd
CFPreference[com.apple.coreservices.useractivityd][kCFPreferencesAnyUser][EnableHandoffInPowerSaverMode] = 1 # Process: /System/Library/PrivateFrameworks/UserActivity.framework/Agents/useractivityd
...
```
Empty file added cfprefsmon/__init__.py
Empty file.
87 changes: 87 additions & 0 deletions cfprefsmon/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from collections import namedtuple

from pymobiledevice3.lockdown import LockdownClient
from pymobiledevice3.services.os_trace import OsTraceService

import click

FORMAT = 'CFPreference[{domain}][{user}][{key}] = {value} # Process: {procname}'

NO_VALUE_PREFIX = 'found no value '
HAS_VALUE_PREFIX = 'looked up value '
FOR_KEY_PREFIX = 'for key '
FOR_KEY_SUFFIX = 'in CFPref'
DOMAIN_PREFIX = '> (Domain: '
USER_PREFIX = ', User: '

DEFAULT_USER = 'kCFPreferencesAnyUser'


@click.command()
@click.option('--udid')
@click.option('--unique', is_flag=True, help='output only unique entries')
@click.option('--color/--no-color', default=True, help='make colored output')
@click.option('--undefined', is_flag=True, help='filter only non-existing keys')
def cli(udid, unique, color, undefined):
lockdown = LockdownClient(udid=udid)
prefs = {}
for entry in OsTraceService(lockdown).syslog():
if entry.label is None:
continue

if entry.label.subsystem != 'com.apple.defaults' or entry.label.category != 'User Defaults':
continue

message = entry.message

if 'cfprefs' not in message.lower():
continue

if not message.startswith(HAS_VALUE_PREFIX) and not message.startswith(NO_VALUE_PREFIX):
continue

# print(message)
user = DEFAULT_USER
value = None

key = message.split(FOR_KEY_PREFIX, 1)[1].split(FOR_KEY_SUFFIX, 1)[0].strip()
domain = message.rsplit(DOMAIN_PREFIX, 1)[1].split(',', 1)[0].strip()
procname = entry.filename
has_value = False

if USER_PREFIX in message:
user = message.rsplit(USER_PREFIX, 1)[1].split(',', 1)[0].strip()

if not user:
user = DEFAULT_USER

if message.startswith(HAS_VALUE_PREFIX):
value = message.split(HAS_VALUE_PREFIX, 1)[1].split(FOR_KEY_PREFIX, 1)[0]
has_value = True

if domain not in prefs:
prefs[domain] = {}

if user not in prefs[domain]:
prefs[domain][user] = []

if unique and key in prefs[domain][user]:
continue

prefs[domain][user].append(key)

if color:
domain = click.style(domain, fg='yellow')
user = click.style(user, fg='bright_green')
key = click.style(key, fg='green')
procname = click.style(procname, fg='magenta')

if not has_value:
value = click.style(value, fg='red')

if (not undefined) or (undefined and not has_value):
print(FORMAT.format(domain=domain, user=user, key=key, value=value, procname=procname))


if __name__ == '__main__':
cli()
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pymobiledevice3
click
55 changes: 55 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from setuptools import setup, find_packages
import os

BASE_DIR = os.path.realpath(os.path.dirname(__file__))
VERSION = '0.0.1'
PACKAGE_NAME = 'cfprefsmon'
PACKAGES = [p for p in find_packages() if not p.startswith('tests')]


def parse_requirements():
reqs = []
if os.path.isfile(os.path.join(BASE_DIR, 'requirements.txt')):
with open(os.path.join(BASE_DIR, 'requirements.txt'), 'r') as fd:
for line in fd.readlines():
line = line.strip()
if line:
reqs.append(line)
return reqs


def get_description():
with open(os.path.join(BASE_DIR, 'README.md'), 'r') as fh:
return fh.read()


if __name__ == '__main__':
setup(
version=VERSION,
name=PACKAGE_NAME,
description='Search for interesting internal preferences inside a connected iDevice',
long_description=get_description(),
long_description_content_type='text/markdown',
cmdclass={},
packages=PACKAGES,
package_data={'': ['*.txt', '*.TXT', '*.json'], },
data_files=[('.', ['requirements.txt'])],
author='DoronZ',
install_requires=parse_requirements(),
entry_points={
'console_scripts': ['cfprefsmon=cfprefsmon.__main__:cli',
],
},
classifiers=[
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
],
url='https://github.com/doronz88/cfprefsmon',
project_urls={
'pymobiledevice3': 'https://github.com/doronz88/cfprefsmon'
},
tests_require=['pytest'],
)

0 comments on commit 4a77933

Please sign in to comment.