Skip to content

Commit 89eea9c

Browse files
authored
Next release (#32)
1 parent 9aa71ff commit 89eea9c

File tree

132 files changed

+15559
-7666
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+15559
-7666
lines changed

.github/workflows/pullrequest.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
info:
1717
- { os: "macOS-latest", target: "x86_64-apple-darwin", cross: false }
1818
- {
19-
os: "ubuntu-latest",
19+
os: "ubuntu-24.04",
2020
target: "x86_64-unknown-linux-gnu",
2121
cross: false,
2222
}
@@ -38,10 +38,18 @@ jobs:
3838
if: matrix.info.os == 'windows-latest'
3939
run: Invoke-WebRequest https://github.com/puffyCid/artemis/releases/download/v0.1.0/script_tester.exe -OutFile .\tests\windows\script_tester.exe
4040

41+
- name: Download script tester binary Linux
42+
if: matrix.info.os == 'ubuntu-24.04'
43+
run: wget -O ./tests/linux/script_tester https://github.com/puffyCid/artemis/releases/download/v0.1.0/script_tester && chmod +x ./tests/linux/script_tester
44+
4145
- name: Install Deno macOS
4246
if: matrix.info.os == 'macOS-latest'
4347
run: brew install deno
4448

49+
- name: Install Deno Linux
50+
if: matrix.info.os == 'ubuntu-24.04'
51+
run: curl -fsSL https://deno.land/install.sh | sh
52+
4553
- name: Install Deno Windows
4654
if: matrix.info.os == 'windows-latest'
4755
run: choco.exe install deno
@@ -53,3 +61,7 @@ jobs:
5361
- name: Compile and run tests Windows
5462
if: matrix.info.os == 'windows-latest'
5563
run: cd tests\windows && .\compile_tests.bat
64+
65+
- name: Compile and run tests Linux
66+
if: matrix.info.os == 'ubuntu-24.04'
67+
run: cd tests/linux && sudo bash compile_tests.sh
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
---
2+
description: How to parse unencrypted iTunes backups!
3+
---
4+
5+
# iTunes Backup Extraction
6+
7+
You can use the artemis API to parse and extract information from unencrypted
8+
iTunes backups! Creating an iOS backup is a common way to collect data from an
9+
iOS device for forensic analysis.
10+
11+
:::info
12+
13+
Support for iOS/iTunes is extremely new and limited. Artemis only supports a few
14+
apps and iOS features. A list of support artifacts/apps can be found
15+
[here](../../Artifacts/ios.md)
16+
17+
If you are looking for a more mature tool, checkout
18+
[iLeapp](https://github.com/abrignoni/iLEAPP)
19+
20+
:::
21+
22+
## Creating the script
23+
24+
Its really easy to start reviewing iTunes backups using the API.
25+
26+
```typescript
27+
import { extractBackup } from "./artemis-api/src/ios/itunes/backup.ts";
28+
import { Format, Output, OutputType } from "./artemis-api/src/system/output.ts";
29+
30+
function main() {
31+
const out: Output = {
32+
name: "iOS_deviceName",
33+
directory: "./tmp",
34+
// JSON format is **strongly** recommended for now
35+
format: Format.JSON,
36+
compress: false,
37+
endpoint_id: "",
38+
collection_id: 0,
39+
output: OutputType.LOCAL,
40+
};
41+
const result = extractBackup(
42+
"./iTunesBackup/00008112-000429AE0C07401E",
43+
out,
44+
);
45+
}
46+
47+
main();
48+
```
49+
50+
The script above will read the iTunes backup directory and parse all supported
51+
apps and backup artifacts in the backup collection.
52+
53+
:::info
54+
55+
Do not forget to transpile the script above to JavaScript as mentioned in
56+
[API](../../Intro/Scripting/bundling.md) section!
57+
58+
**Strongly** suggest you `minify` the transpiled script.\
59+
It will make it alot smaller!
60+
61+
:::
62+
63+
## Script Output
64+
65+
The way artemis outputs data is unique for the iTunes API. Normally, artemis
66+
will output all data to single folder provided in the `Output` object.
67+
68+
However, since artemis is parsing multiple apps and other artifacts, parsed data
69+
will placed in its own sub-directory.
70+
71+
If you run the script above the output structure will look like the following:
72+
73+
- Root folder - **./tmp**
74+
- Subfolders:
75+
- ./tmp/iOS_deviceName: Contains metadata associated with iTunes backup
76+
- ./tmp/apps/iOS_deviceName_app_or_artifact_name. Ex:
77+
`iOS_deviceName_com.zhiliaoapp.musically`
78+
79+
Each subfolder will contain you JSON output
80+
81+
## Adding new apps or artifacts
82+
83+
Adding support for new apps or artifacts is not too challenging :)
84+
85+
1. Make sure you have the tool prerequisites installed (Deno, VSCodium (or
86+
VSCode))
87+
2. Clone the artemis-api repo (https://github.com/puffyCid/artemis-api.git)
88+
3. To add support for a new app, create a folder under
89+
`./src/ios/apps/<app name>`\
90+
To add support for a new artifact, create a folder under
91+
`./src/ios/domains/<artifact domain name>`
92+
93+
## App or artifact code structure
94+
95+
Once you have identified an app you want to parse you will need to write some
96+
TypeScript code in order to plug it in to the artemis API.
97+
98+
Lets say we want to add support for the DuckDuckGo browser app. We would create
99+
a typescript (ts) file under `./src/ios/apps/duckduckgo/duck.ts`.
100+
101+
:::note
102+
103+
You can name you folder and ts file anything you want
104+
105+
:::
106+
107+
In our new file we would add the following code
108+
109+
```typescript
110+
import {
111+
FileType,
112+
ManifestApp,
113+
} from "../../../../types/ios/itunes/manifest.ts";
114+
import { Output, outputResults } from "../../../system/output.ts";
115+
import { IosError } from "../../error.ts";
116+
import { parseManifestAppPlist } from "../../itunes/apps.ts";
117+
118+
/**
119+
* Function to extract DuckDuckGo browser info
120+
* @param app_paths Array of `ManifestApp`
121+
* @param db_path iTunes backup directory
122+
* @param output `Output` configuration object
123+
*/
124+
export function extractDuckDuckGo(
125+
app_paths: ManifestApp[],
126+
db_path: string,
127+
output: Output,
128+
) {
129+
for (const path of app_paths) {
130+
if (path.file_type != FileType.IsFile) {
131+
continue;
132+
}
133+
// Function to parse the binary plist in the Manifest.db file. Contains FileMetadata
134+
const info = parseManifestAppPlist(path.file);
135+
if (info instanceof IosError) {
136+
continue;
137+
}
138+
139+
const target = `${db_path}/${path.directory}/${path.fileID}`;
140+
console.log(info.path);
141+
console.log(target);
142+
}
143+
}
144+
```
145+
146+
The code above registers a function called `extractDuckDuckGo` and pass several
147+
parameters to the function. We will review the parameters later, but you do not
148+
need to know how to obtain them.
149+
150+
Afte register our function, we start to loop through our array of app_paths.
151+
These paths are the directories associated withe our app. Each directory should
152+
have an associated binary plist that we need to parse using
153+
`parseManifestAppPlist`.
154+
155+
:::note
156+
157+
We only want to parse files! So we skip non-file related entries such as
158+
directories
159+
160+
:::
161+
162+
:::info
163+
164+
iTunes backup files and directories names are hashed! In order to determine the
165+
original name we need to call `parseManifestAppPlist`!
166+
167+
:::
168+
169+
Next we specify the target iTunes backup file:
170+
``const target = `${db_path}/${path.directory}/${path.fileID}`;``
171+
172+
Then we print the target file (path of hashed names and directories) and the
173+
un-hashed names
174+
175+
If you transpile and run the code above you should see something like below:
176+
177+
```
178+
[runtime]: "Library/Preferences/com.duckduckgo.blocker-list.etags.plist"
179+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/7e/7e65b6f36849e8431a36186ddf98019af8487f1d"
180+
[runtime]: "Library/Preferences/com.apple.EmojiCache.plist"
181+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/96/962a40518bc47a929fa53a208b2250e4937add6a"
182+
[runtime]: "Library/Preferences/com.duckduckgo.app.adClickAttribution.plist"
183+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/0a/0a54b7c56e482059cfb55968b1305a15e948453a"
184+
[runtime]: "Library/WebKit/WebsiteData/Default/QkkulCe8Q-EdXJ986IlKrwKGIychU0X2UP4JUpfNScs/QkkulCe8Q-EdXJ986IlKrwKGIychU0X2UP4JUpfNScs/origin"
185+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/cd/cd330b4833dbc9f7630c774f45ea1ec746eaec01"
186+
[runtime]: "Library/WebKit/WebsiteData/Default/salt"
187+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/05/05fd1262114b7103c4a5fbb1b6e08e52d40d546f"
188+
[runtime]: "Library/WebKit/GeolocationSites.plist"
189+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/88/8888b54a27c0f79e99567e6329b95378f8901a0c"
190+
[runtime]: "Library/WebKit/WebsiteData/SearchHistory/RecentSearches.plist"
191+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/c7/c77e5f0c616494ccfee9c7fa381646c54bfb13b8"
192+
[runtime]: "Library/WebKit/ContentRuleLists/ContentRuleList-blockImageRules"
193+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/a0/a08cfdf4b2d3cdce9fbf6bc7afbcf7565b65492a"
194+
[runtime]: "Library/Preferences/group.com.duckduckgo.app.plist"
195+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/d9/d956029361b6990e109d1d8cc47c8b0780fa0758"
196+
[runtime]: "Library/Application Support/.tipkit/tips-store.db"
197+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/2b/2bb3cd6079dac3dc4fbd757e1a9730458056f6a3"
198+
[runtime]: "Library/WebKit/ContentRuleLists/ContentRuleList-%22TrackerDataSet%22%22A_%2275cff4e36f76d9a81af0643d775008c9%22%22cbc7891482cdc5656356758fbf4df7d672ce2933%22%2265d5e346d5f4b32b8b5f813d753c8718%22%22%22"
199+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/27/272f7a61c6b687508c7a9c30f91cc955a1d418cd"
200+
[runtime]: "Library/Preferences/HKE973VLUW.com.duckduckgo.subscriptions.plist"
201+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/34/346893e9861467096e4bd75a103ec913e000a9c8"
202+
[runtime]: "Library/Application Support/atb-present.marker"
203+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/95/95d9c13c5075b50fe82e77a63dc33a49edd9698d"
204+
[runtime]: "Library/WebKit/WebsiteData/Default/QkkulCe8Q-EdXJ986IlKrwKGIychU0X2UP4JUpfNScs/QkkulCe8Q-EdXJ986IlKrwKGIychU0X2UP4JUpfNScs/CacheStorage/salt"
205+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/28/284d57dd57fbb5b2ba47df75061d54b029d349cd"
206+
[runtime]: "Library/Preferences/com.duckduckgo.mobile.ios.plist"
207+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/f8/f881608e2754551e1695a1bab51b8b11c8b5a3bc"
208+
[runtime]: "Library/Preferences/com.duckduckgo.unique.pixel.storage.plist"
209+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/7e/7ee08df288b84e89aba7e642620731b032be42d5"
210+
[runtime]: "Library/Preferences/com.duckduckgo.pixel.storage.plist"
211+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/68/68a54dda6529c4364087fa47776d8bf312cb6a71"
212+
[runtime]: "Library/WebKit/ContentRuleLists/ContentRuleList-%22Attribution_TrackerDataSet%22%22A_%2275cff4e36f76d9a81af0643d775008c9%22%22cbc7891482cdc5656356758fbf4df7d672ce2933%22%2265d5e346d5f4b32b8b5f813d753c8718%22%22%22"
213+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/b6/b641cda8a7bb7d542d604e2441ca05b0a7b3cad9"
214+
[runtime]: "Library/WebKit/WebsiteData/ResourceLoadStatistics/observations.db"
215+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/0e/0eeba21e901d1c692c861fa478d3b9021352f5be"
216+
[runtime]: "Library/Application Support/ad-attribution-successful.marker"
217+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/3c/3c73a053786b0cfbddb873791a5af1ff575686a8"
218+
[runtime]: "Library/Preferences/com.duckduckgo.daily.pixel.storage.plist"
219+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/0e/0e7c2c955a0e18fe284fa6a96787d9db7e2257d7"
220+
[runtime]: "Library/Cookies/Cookies.binarycookies"
221+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/1c/1c2937886859a739a9746411d9a25d3907de4ac1"
222+
[runtime]: "Library/Application Support/History.sqlite"
223+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/2a/2a984202263e5aedd67a20d6233f115783cddd65"
224+
[runtime]: "Library/Preferences/com.duckduckgo.app.toggleProtectionsCounter.plist"
225+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/f1/f1b0e539a2f0d8a3897fe0331882bc07f3ef82ed"
226+
[runtime]: "Library/WebKit/WebsiteData/MediaKeys/v1/salt"
227+
[runtime]: "./itunesBackupDirectory/00008112-000429AE0C07401E/ca/caa12f6b21d5beb6938d79a9ea8d4b2b503d0223"
228+
```
229+
230+
## Research!
231+
232+
Now is the challenging part! We need to research what file we may want to parse!
233+
The most common types of files you will encouter are JSON, plist, and sqlite
234+
databases.
235+
236+
Lets look at the `GeolocationSites.plist` file. It looks interesting. Since its
237+
a plist file we will need to import the plist parsing function to our code
238+
239+
```typescript
240+
for (const path of app_paths) {
241+
if (path.file_type != FileType.IsFile) {
242+
continue;
243+
}
244+
// Function to parse the binary plist in the Manifest.db file. Contains FileMetadata
245+
const info = parseManifestAppPlist(path.file);
246+
if (info instanceof IosError) {
247+
continue;
248+
}
249+
250+
const target = `${db_path}/${path.directory}/${path.fileID}`;
251+
if (info.path.includes("GeolocationSites.plist")) {
252+
// Make sure to provide the target variable! This the full path the to iTunes backup hashed filename
253+
const result = getPlist(target);
254+
outputResults(JSON.stringify(result), "duckduckgo_geosites", output);
255+
}
256+
console.log(info.path);
257+
console.log(target);
258+
}
259+
```
260+
261+
The additional code we added will parse the `GeolocationSites.plist` file and
262+
output the results to a JSON file!
263+
264+
We would repeat this process for each file we are interested for the DuckDuckGo
265+
app.
266+
267+
## Conclusion
268+
269+
The final step is to make artemis aware of the `extractDuckDuckGo` function.\
270+
Navigate to the file `./src/ios/itunes/apps.ts` and to `extractAppInfo`.
271+
272+
You should see something like below:
273+
274+
```typescript
275+
/**
276+
* Function to parse supported apps and domains
277+
* @param paths Array of `ManifestApp`
278+
* @param namespace App or domain name
279+
* @param db_path iTunes backup directory
280+
* @param output `Output` object
281+
*/
282+
export function extractAppInfo(
283+
paths: ManifestApp[],
284+
namespace: string,
285+
db_path: string,
286+
output: Output,
287+
) {
288+
switch (namespace) {
289+
case "com.amazon.echo":
290+
extractAmazonEcho(paths, db_path, output);
291+
break;
292+
case "us.zoom.videomeetings":
293+
extractZoom(paths, db_path, output);
294+
break;
295+
case "co.hinge.mobile.ios":
296+
extractHingeInfo(paths, db_path, output);
297+
break;
298+
case "HomeDomain":
299+
extractHomeDomain(paths, db_path, output);
300+
break;
301+
case "RootDomain":
302+
extractRootDomain(paths, db_path, output);
303+
break;
304+
}
305+
}
306+
```
307+
308+
We just need to insert domain name for the DuckDuckGo app and add our function!
309+
310+
```typescript
311+
switch (namespace) {
312+
case "com.amazon.echo":
313+
extractAmazonEcho(paths, db_path, output);
314+
break;
315+
case "us.zoom.videomeetings":
316+
extractZoom(paths, db_path, output);
317+
break;
318+
case "com.duckduckgo.mobile.ios": // <-------------- Our function is registered!
319+
extractDuckDuckGo(paths, db_path, output);
320+
break;
321+
case "co.hinge.mobile.ios":
322+
extractHingeInfo(paths, db_path, output);
323+
break;
324+
case "HomeDomain":
325+
extractHomeDomain(paths, db_path, output);
326+
break;
327+
case "RootDomain":
328+
extractRootDomain(paths, db_path, output);
329+
break;
330+
}
331+
```
332+
333+
:::info
334+
335+
If you do not know the domain name of the app. You can find it in the output
336+
after running your script and calling `extractBackup` once.
337+
338+
:::

0 commit comments

Comments
 (0)