Skip to content

Instantly share code, notes, and snippets.

@mickael9
Last active August 26, 2024 08:55
Show Gist options
  • Save mickael9/0b902da7c13207d1b86e to your computer and use it in GitHub Desktop.
Save mickael9/0b902da7c13207d1b86e to your computer and use it in GitHub Desktop.
Bitrock unpacking script
#!/usr/bin/env tclkit
#
# Bitrock unpacking script
#
# This script must be executed using 32-bit tclkit
#
# Author : mickael9 <mickael9 at gmail dot com>
#
# Latest version can be found at:
# https://gist.github.com/mickael9/0b902da7c13207d1b86e
source /usr/bin/sdx.kit
if {$argc < 2} {
puts "Usage: $argv0 installerFile outputDirectory"
exit 1
}
set installerFile [lindex $argv 0]
set destDir [lindex $argv 1]
set installerMount /installer
set dataMount /installerData
vfs::mk4::Mount $installerFile $installerMount -readonly
lappend auto_path $installerMount/libraries/
package require vfs::cookfs
catch {package require Tcllzmadec}
# progress from http://wiki.tcl.tk/16939 (sligtly modified)
# thanks to the author
proc progress {cur tot} {
# set to total width of progress bar
set total 76
if {$cur == $tot} {
# cleanup
set str "\r[string repeat " " [expr $total + 4]]\r"
} else {
set half [expr {$total/2}]
set percent [expr {100.*$cur/$tot}]
set val (\ [format "%6.2f%%" $percent]\ )
set str "\r|[string repeat = [
expr {round($percent*$total/100)}]][
string repeat { } [expr {$total-round($percent*$total/100)}]]|"
set str "[string range $str 0 $half]$val[string range $str [expr {$half+[string length $val]-1}] end]"
}
puts -nonewline stderr $str
}
# Read cookfs options
set optionsFile [open $installerMount/cookfsinfo.txt]
set options [read $optionsFile]
close $optionsFile
# Read the manifest
set manifestFile [open $installerMount/manifest.txt]
set manifest [read $manifestFile]
close $manifestFile
# Mount the files to $dataMount
vfs::cookfs::Mount {*}$options $installerFile $dataMount
puts "Creating directories..."
foreach {fileName props} $manifest {
set type [lindex $props 0]
if {$type == "directory"} {
set mode [lindex $props 1]
file mkdir $destDir/$fileName
file attributes $destDir/$fileName -permissions $mode
}
}
puts "Unpacking files, please wait..."
set entryCount [expr [llength $manifest] / 2]
set entryIndex 0
foreach {fileName props} $manifest {
set type [lindex $props 0]
if {$type == "file"} {
set mode [lindex $props 1]
set sizes [lindex $props 4]
set nparts [llength $sizes]
set index 1
file mkdir [file dirname $destDir/$fileName]
file copy -force $dataMount/$fileName $destDir/$fileName
if {$nparts > 0} {
set fp [open $destDir/$fileName a]
fconfigure $fp -translation binary
while {$index < $nparts} {
set chunkName $dataMount/${fileName}___bitrockBigFile$index
set fp2 [open $chunkName r]
fconfigure $fp2 -translation binary
puts -nonewline $fp [read $fp2]
close $fp2
incr index
}
close $fp
}
file attributes $destDir/$fileName -permissions $mode
}
incr entryIndex
progress $entryIndex $entryCount
}
puts "Creating links..."
foreach {fileName props} $manifest {
set type [lindex $props 0]
if {$type == "link"} {
set linkTarget [lindex $props 1]
file delete $destDir/$fileName
file link -symbolic $destDir/$fileName $linkTarget
}
}
puts "Done"
@zhangyoufu
Copy link

And I prefer some hack on the installer/pak to turn it into a tclkit.
Something like sed --in-place --null-data --expression='/^if {\[file isfile \[file join \$::tcl::kitpath main.tcl/{s/^./\x1A/}' installer

@mickael9
Copy link
Author

@zhangyoufu that's cool I'm stealing this!
Wold you care to explain why this works ? Is \x1A considered a comment character?

@zhangyoufu
Copy link

@mickael9 It seems that Tcl treat \x1A (Ctrl-Z) as eofchar by default.

By terminate execution before reaching main.tcl, an installer is effectively a tclkit without payload script to execute.

I really like this idea because I don’t have to looking for dependencies. The installer already packs them together. You only need to set auto_path correctly and load them.

I use paks/linux-x64-noupx.pak & paks/optional.pak from InstallBuilder installation directory. It’s handy for CI, and it works pretty well against win/mac installers.

@banxian
Copy link

banxian commented Aug 10, 2020

@zhangyoufu excellent hack , seems it applies Tcl_EvalEx invoke in TclKit_AppInit?
I have never used tcl before, my goal is extract payload encryption algorithm (I guess it decrypted by tcltwofish10.dll and cookfs14.dll), so I decide hook Tcl_CreateObjCommand in installer stub and hijack ::sha2::sha256c_update/::tcltwofish::decrypt to insert logger.
I think my way is somewhat ugly, could you point me better tcl style methods?

PS: I can't find maui::util package over web. is it contains in sdx.kit or somewhere else?
thank you

@zhangyoufu
Copy link

zhangyoufu commented Aug 10, 2020

@banxian maui is a proprietary package of Bitrock InstallBuilder, you can find it inside the metakit VFS.

I posted my code at https://gist.github.com/zhangyoufu/b85496abe9d9301e2d422858330a471a

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