Skip to content

Instantly share code, notes, and snippets.

@yvesf
Created May 2, 2015 20:35
Show Gist options
  • Save yvesf/d8cf8d647c88513a5e5e to your computer and use it in GitHub Desktop.
Save yvesf/d8cf8d647c88513a5e5e to your computer and use it in GitHub Desktop.
Parse google-chrome .pak files in shell
#!/bin/bash
# Parse google-chrome .pak resourcefiles
parse_int() {
( echo "ibase=16; "; cat; echo -e "\n") | bc
}
endian_conversion() {
if [[ "$1" == "little" ]]; then
tac
else
cat
fi
}
read_bytes() {
local length=$1
local endian=$2
local i=0
while [ $i -lt $length ]; do
read -r -d ' ' byte
[ "$byte" == "" ] && read -r -d ' ' byte
echo $byte
let i+=1
done \
| endian_conversion "$endian" \
| tr -d '\n'
}
parse() {
local format=$1
local endian=big
local i=0
while [[ $i -lt ${#format} ]]; do
case "${format:$i:1}" in
"<") endian="little";;
">") endian="big";;
"I") read_bytes "4" "$endian" | parse_int; let offset+=4;;
"H") read_bytes "2" "$endian" | parse_int; let offset+=2;;
"B") read_bytes "1" "$endian" | parse_int; let offset+=1;;
*)
echo "Invalid format: ${format:$i:1}" >&2;;
esac
let i+=1
done | tr '\n' ' '
}
read_file() {
local file=$1
local offset=$2
local format=$3
dd if=$file bs=1 skip=$offset count=$(format_len "$format") 2>/dev/null \
| od --output-duplicates --format=x1 --address-radix=n \
| tr 'a-z' 'A-Z' | tr -d '\n'
}
parse_file() {
read_file "$1" "$2" "$3" | parse "$3"
}
format_len() {
local format=$1
local len=0
local i=0
while [[ $i -lt ${#format} ]]; do
case "${format:$i:1}" in
"I") let len+=4 ;;
"H") let len+=2 ;;
"B") let len+=1 ;;
"<"|">") ;;
*) echo "Invalid format: ${format:$i:1}" >&2;;
esac
let i+=1
done
echo "$len"
}
##################
header_size=$(format_len "<IIB")
entry_size=$(format_len "<HI")
read -r version num_entries encoding < \
<(parse_file "en-US.pak" 0 "<IIB")
if [ "$version" != "4" ]; then
echo "Invalid version: $version" >&2
exit 1
fi
if [ "$encoding" != "1" ]; then
echo "Invalid encoding: $encoding" >&2
exit 1
fi
pos=$header_size
i=0
while [ $i -lt $num_entries ]; do
read -r id offset next_id next_offset < <(parse_file "en-US.pak" $pos "<HIHI")
let pos+=entry_size
let entry_len=next_offset-offset
echo "$id: $(dd if=en-US.pak bs=1 count=$entry_len skip=$offset 2>/dev/null)"
let i+=1
done
@apkfx
Copy link

apkfx commented Apr 22, 2017

By default this script only extrack en-US.pak file. How to extrack other file without edit the script. So like this:

./parse-chrome-pak.sh en-US.pak
./parse-chrome-pak.sh id.pak

Thank you

Copy link

ghost commented Oct 13, 2022

for Windows you can also use 7zip with grit7z placed in formats folder
or this bundle. should also work with Linux+wine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment