diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..9e8e772 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,39 @@ +SHELL = /bin/bash + +DMG:=osxupd10.11.2.dmg +OSX_DRV:=AppleCameraInterface +OSX_DRV_DIR:=System/Library/Extensions/AppleCameraInterface.kext/Contents/MacOS + +RANGE:=420107885-421933300 + +URL:=https://support.apple.com/downloads/DL1849/en_US/$(DMG) +FILE:=$(OSX_DRV_DIR)/$(OSX_DRV) + +ifneq ("$(wildcard /usr/lib/firmware)", "") + FW_DIR_BASE:="/usr/lib/firmware" +else + FW_DIR_BASE:="/lib/firmware" +endif + +FW_DIR:="$(FW_DIR_BASE)/facetimehd" + +all: $(OSX_DRV) + @./extract-firmware.sh -x "$(OSX_DRV)" + +$(OSX_DRV): + @# Ty to wvengen, see: https://github.com/patjak/bcwc_pcie/issues/14#issuecomment-167446787 + @echo "Dowloading the driver, please wait..." + @(curl -s -L -r "$(RANGE)" "$(URL)" | xzcat -q | cpio --format odc -i -d "./$(FILE)") &> /dev/null || true + @mv "$(FILE)" . + @rmdir -p "$(OSX_DRV_DIR)" + +install: + @echo "Copying firmware into '$(DESTDIR)/$(FW_DIR)'" + @install -dm755 "$(DESTDIR)/$(FW_DIR)" + @install -m644 "firmware.bin" "$(DESTDIR)/$(FW_DIR)/firmware.bin" + +.PHONY: clean +clean: + rm -f AppleCamera{Interface,.sys} + rm -f firmware.bin + diff --git a/firmware/extract-firmware.sh b/firmware/extract-firmware.sh new file mode 100755 index 0000000..de07fd2 --- /dev/null +++ b/firmware/extract-firmware.sh @@ -0,0 +1,279 @@ +#!/bin/bash + +# Known driver hashes +# +# NOTE: use sha256 checksums as they are more robust that md5 against collisions +hash_drv_wnd_105='6ec37d48c0764ed059dd49f472456a4f70150297d6397b7cc7965034cf78627e' +hash_drv_wnd_138='7044344593bfc08ab9b41ab691213bca568c8d924d0e05136b537f66b3c46f31' +hash_drv_osx_143_1='4667e6828f6bfc690a39cf9d561369a525f44394f48d0a98d750931b2f3f278b' +hash_drv_osx_143_2='d4650346c940dafdc50e5fcbeeeffe074ec359726773e79c0cfa601cec6b1f08' + +hash_fw_wnd_105='dabb8cf8e874451ebc85c51ef524bd83ddfa237c9ba2e191f8532b896594e50e' +hash_fw_wnd_138='ed75dc37b1a0e19949e9e046a629cb55deb6eec0f13ba8fd8dd49b5ccd5a800e' +hash_fw_osx_143_1='e3e6034a67dfdaa27672dd547698bbc5b33f47f1fc7f5572a2fb68ea09d32d3d' +hash_fw_osx_143_2='e3e6034a67dfdaa27672dd547698bbc5b33f47f1fc7f5572a2fb68ea09d32d3d' + +# Driver names +declare -A known_hashes=( + ["$hash_drv_wnd_105"]='Windows Boot Camp 5.1.5722' + ["$hash_drv_wnd_138"]='Windows Boot Camp Update Jul 29, 2015' + ["$hash_drv_osx_143_1"]='OS X, El Capitan' + ["$hash_drv_osx_143_2"]='OS X, El Capitan 10.11.2' +) + +# Offset in bytes of the firmware inside the driver +declare -A firmw_offsets=( + ["$hash_drv_wnd_105"]=78208 + ["$hash_drv_wnd_138"]=85296 + ["$hash_drv_osx_143_1"]=81920 + ["$hash_drv_osx_143_2"]=81920 +) + +# Size in bytes of the firmware inside the driver +declare -A firmw_sizes=( + ["$hash_drv_wnd_105"]=1523716 + ["$hash_drv_wnd_138"]=1421316 + ["$hash_drv_osx_143_1"]=603715 + ["$hash_drv_osx_143_2"]=603715 +) + +# Compression method used to store the firmware inside the driver +declare -A compression=( + ["$hash_drv_wnd_105"]='cat' + ["$hash_drv_wnd_138"]='cat' + ["$hash_drv_osx_143_1"]='gzip' + ["$hash_drv_osx_143_2"]='gzip' +) + +declare -A firmw_hashes=( + ["$hash_fw_wnd_105"]='1.05' + ["$hash_fw_wnd_138"]='1.38' + ["$hash_fw_osx_143_1"]='1.43.1' + ["$hash_fw_osx_143_2"]='1.43.2' +) + +printHelp() +{ + cat < $*" +} + +msg2() +{ + echo " --> $*" +} + +err() +{ + echo "Error: $*" +} + +hasProgram() +{ + if ! which "$1" &> /dev/null; then + err "'$1' needed but not found!" + exit 1 + fi +} + +checkDmgPrerequisites() +{ + hasProgram "7z" + hasProgram "cpio" + hasProgram "head" + hasProgram "mkdir" + hasProgram "pbzx" + hasProgram "sha256sum" + hasProgram "tail" + hasProgram "xar" +} + +checkPrerequisites() +{ + hasProgram "awk" + hasProgram "dd" + hasProgram "sha256sum" + hasProgram "zcat" +} + +getCheckSum() +{ + sha256sum $1 | awk '{ print $1 }' +} + +checkDriverHash() +{ + # computing the hash for the input file + driver_hash="$(getCheckSum $1)" + + # checking if it is among the known hashes + for cur_hash in "${!known_hashes[@]}"; do + if [[ "$driver_hash" == "$cur_hash" ]]; then + echo "Found matching hash from ${known_hashes[$cur_hash]}" + return + fi + done + + err "Mismatching driver hash for $1" + err "The uknown hash is ${driver_hash}" + err "No firmware extracted!" + exit 1 +} + +checkFirmwareHash() +{ + # computing the hash for the input file + fw_hash="$(getCheckSum $1)" + + # checking if it is among the known hashes + for cur_hash in "${!firmw_hashes[@]}"; do + if [[ "$fw_hash" == "$cur_hash" ]]; then + msg2 "Extracted firmware version ${firmw_hashes[$cur_hash]}" + return 0 + fi + done + + err "Mismatching firmware hash ${firm_hash}" + err "No firmware extracted!" + return 1 +} + +extractFirmware() +{ + msg "Extracting firmware..." + dd bs=1 skip=$3 count=$4 if=$1 of="$2.tmp" &> /dev/null + + msg2 "Decompressing the firmware using $5..." + case "$5" in + "gzip") + zcat "$2.tmp" > "$2" + ;; + "cat") + cat "$2.tmp" > "$2" + ;; + esac + + msg2 "Deleting temporary files..." + rm "$2.tmp" +} + +decompress_dmg() +{ + msg "Extracting the driver from $1..." + + msg2 "Creating temporary directories..." + mkdir -p "${_main_dir}/temp" + cd "${_main_dir}/temp" + + msg2 "Decompressing the image..." + 7z e -y "${_main_dir}/$1" "5.hfs" > /dev/null + + msg2 "Extracting upadate package..." + tail -c +189001729 "5.hfs" | head -c 1469917156 > OSXUpd.xar + rm -f "5.hfs" + + msg2 "Uncompressing XAR archive..." + xar -x -f "OSXUpd.xar" + rm -f "OSXUpd.xar" + + msg2 "Decoding Payload..." + pbzx "OSXUpd"*.pkg"/Payload" > /dev/null + rm "OSXUpdCombo10.11.2.pkg/Payload" + + msg2 "Decompressing archives..." + cd "OSXUpdCombo10.11.2.pkg" + find . -name "Payload.part*.xz" -exec xz --decompress --verbose {} \; + cat "Payload.part"* | cpio -id &> /dev/null + cp "./System/Library/Extensions/AppleCameraInterface.kext/Contents/MacOS/AppleCameraInterface" \ + "${_main_dir}" + msg2 "Cleaning up..." + rm -rf "${_main_dir}/temp" +} + +extract_from_osx() +{ + + echo "" + checkDriverHash "$1" + + offset="${firmw_offsets[$driver_hash]}" + size="${firmw_sizes[$driver_hash]}" + comp_method="${compression[$driver_hash]}" + + extractFirmware "$1" "firmware.bin" "$offset" "$size" "$comp_method" + + checkFirmwareHash "firmware.bin" +} + +main() +{ + echo "" + + # Parsing arguments + while [[ $# > 1 ]]; do + case $1 in + -h|--help) + printHelp + exit 1 + ;; + --dmg) + dmg_file="$2" + shift + ;; + -x) + drv_file="$2" + shift + ;; + esac + shift + done + + checkPrerequisites + + if [[ ! -z "$dmg_file" ]]; then + checkDmgPrerequisites + decompress_dmg "$dmg_file" + fi + + cd "${_main_dir}" + + if [[ ! -z "$drv_file" ]]; then + extract_from_osx "$drv_file" + fi + + echo "" + exit 0 +} + +_main_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +main "$@" diff --git a/firmware/extract_from_osx.sh b/firmware/extract_from_osx.sh deleted file mode 100755 index 324e2a5..0000000 --- a/firmware/extract_from_osx.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -IN=AppleCameraInterface -OUT=firmware.bin - -OSX_HASH=d1db66d71475687a5873dab10a345e2d -FW_HASH=4e1d11e205e5c55d128efa0029b268fe -HASH=$(md5sum $IN | awk '{ print $1 }') - -OFFSET=81920 -SIZE=603715 - -if [ "$OSX_HASH" != "$HASH" ] -then - echo -e "Mismatching driver hash for $IN ($HASH)" - echo -e "No firmware extracted!" - exit 1 -fi - -echo -e "Found matching hash ($HASH)" - -dd bs=1 skip=$OFFSET count=$SIZE if=$IN of=$OUT.gz &> /dev/null -gunzip $OUT.gz - -RESULT=$(md5sum $OUT | awk '{ print $1 }') - -if [ "$RESULT" != "$FW_HASH" ] -then - echo -e "Firmware hash mismatch ($RESULT)" - echo -e "No firmware extracted!" - exit 1; -fi - -echo -e "Firmware successfully extracted ($RESULT)" - -exit 0