Last active
May 14, 2020 20:36
-
-
Save quarnster/11189901 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// GOOS=linux GOARCH=386 go build verify.go && ftp -u boxeebox:/tmp/ verify | |
// | |
// This tool verifies the boxeebox boot block, based on | |
// findings from running the "bootblockverifier" tool found | |
// in the boxeebox rma image (see http://www.boxeeboxwiki.org/rma). | |
// | |
// ##################### WARNING!!!! ###################### | |
// # Whether it's possible to use this information to # | |
// # actually replace the current bootloader with a # | |
// # custom version is at the moment unknown. Use at # | |
// # your own risk!! # | |
// ##################### WARNING!!!! ###################### | |
// | |
// Running this tool alone should be safe as it only performs | |
// a read operation from nandflash, so should not be able to | |
// break anything. | |
// | |
// usage: go run verify.go | |
// | |
package main | |
import ( | |
"bytes" | |
"crypto" | |
"crypto/rsa" | |
"crypto/sha256" | |
"encoding/hex" | |
"fmt" | |
"github.com/quarnster/util/encoding/binary" | |
"io" | |
"log" | |
"math/big" | |
"syscall" | |
"unsafe" | |
) | |
type ( | |
Header struct { | |
Unknown [2]uint32 | |
SomeSize uint32 | |
Unknown2 uint32 | |
VendorId uint32 | |
Date uint32 | |
Unknown3 [4]uint32 | |
BodyLocation uint32 // "hex address of body location" | |
SignatureLocation uint32 | |
KeyLocation uint32 // "(optional)hex address of Encrypted Ke location" | |
} | |
BLOCKNODE uint32 | |
PAGENUMTYPE uint16 | |
PAGESIZETYPE uint16 | |
BLOCKSIZETYPE uint32 | |
ADDRESSTYPE uintptr | |
BOOT_BLOCKTABLE_IO_CMD struct { | |
btEntrySizeInBits byte | |
btEntryNum uint16 | |
AddrInRam ADDRESSTYPE | |
} | |
BOOT_BLOCKTABLE_INFO struct { | |
bt_sig [4]byte | |
nSpareSkipByteInZone1, nSpareSkipByteInZone0, reserve3, btEntrySizeInBits byte | |
btEntryNum, btOffsetInBytes, md5OffsetInBytes, md5SizeInBytes uint16 | |
} | |
SPEC_IO_CMD struct { | |
NumPagesToTransfer uint32 | |
AddrInRam ADDRESSTYPE | |
StartBlockNum BLOCKNODE | |
StartPageNum uint16 | |
} | |
DEVICE_INFO struct { | |
wDeviceMaker uint16 | |
wDeviceType uint32 | |
wSpectraStartBlock BLOCKNODE | |
wSpectraEndBlock BLOCKNODE | |
wBlockNum BLOCKNODE | |
wTotalBlocks BLOCKNODE | |
wPagesPerBlock PAGENUMTYPE | |
wPageSize PAGESIZETYPE | |
wPageDataSize PAGESIZETYPE | |
wPageSpareSize PAGESIZETYPE | |
wNumPageSpareFlag uint16 | |
wECCBytesPerSector uint16 | |
wBlockSize BLOCKSIZETYPE | |
wBlockDataSize BLOCKSIZETYPE | |
wDataBlockNum BLOCKNODE | |
bPlaneNum byte | |
wDeviceMainAreaSize uint16 | |
wDeviceSpareAreaSize uint16 | |
wDevicesConnected uint16 | |
wDeviceWidth uint16 | |
wHWRevision uint16 | |
wHWFeatures uint16 | |
wONFIDevFeatures uint16 | |
wONFIOptCommands uint16 | |
wONFITimingMode uint16 | |
wONFIPgmCacheTimingMode uint16 | |
MLCDevice uint16 | |
wSpareSkipBytes uint16 | |
} | |
) | |
const ( | |
GLOB_SBD_IOCTL_RD_MAIN = 0x8810 + iota | |
GLOB_SBD_IOCTL_WR_MAIN | |
GLOB_SBD_IOCTL_ERASE | |
GLOB_SBD_IOCTL_RD_ID | |
GLOB_SBD_IOCTL_CHK_BADBLK | |
GLOB_SBD_IOCTL_RD_MAIN_SPARE_RAW | |
GLOB_SBD_IOCTL_WR_MAIN_SPARE_RAW | |
) | |
const ( | |
GLOB_SBD_IOCTL_ERASE_RAW = 0x9910 + iota | |
GLOB_SBD_IOCTL_RD_BT | |
GLOB_SBD_IOCTL_CREATE_BT_DUMMY | |
GLOB_SBD_IOCTL_CREATE_BT_BYERASE | |
GLOB_SBD_IOCTL_CREATE_BT_BYMARKER | |
GLOB_SBD_IOCTL_ERASE_BYMARKER | |
) | |
func leswap(data []byte) (cop []byte) { | |
cop = make([]byte, len(data)) | |
for i := 0; i < len(data); i += 4 { | |
cop[i+0], cop[i+1], cop[i+2], cop[i+3] = data[i+3], data[i+2], data[i+1], data[i+0] | |
} | |
return | |
} | |
func ioctl(device int, cmd uintptr, data unsafe.Pointer) (int, error) { | |
a, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(device), cmd, uintptr(data)) | |
var err error | |
if errno != 0 { | |
err = errno | |
} | |
return int(a), err | |
} | |
func readBootBlock() ([]byte, error) { | |
var ( | |
id DEVICE_INFO | |
read SPEC_IO_CMD | |
) | |
device, err := syscall.Open("/dev/spectra", syscall.O_RDONLY, 0) | |
if err != nil || device < 0 { | |
return nil, fmt.Errorf("Device is negative: %d, %s", device, err) | |
} | |
defer syscall.Close(device) | |
fmt.Println("device:", device) | |
if _, err := ioctl(device, GLOB_SBD_IOCTL_RD_ID, unsafe.Pointer(&id)); err != nil { | |
return nil, err | |
} | |
fmt.Printf("Id: %+v\n", id) | |
data := make([]byte, int(id.wPageSize)*int(id.wPagesPerBlock)) | |
read.StartBlockNum = 0 | |
read.AddrInRam = ADDRESSTYPE(unsafe.Pointer(&data[0])) | |
read.NumPagesToTransfer = uint32(id.wPagesPerBlock) | |
ioctl(device, GLOB_SBD_IOCTL_RD_MAIN, unsafe.Pointer(&read)) | |
fmt.Printf("Boot block: %+v\n", *(*BOOT_BLOCKTABLE_INFO)(unsafe.Pointer(&data[32]))) | |
read.StartBlockNum = 8 | |
if i, err := ioctl(device, GLOB_SBD_IOCTL_RD_MAIN, unsafe.Pointer(&read)); i == -1 || err != nil { | |
return nil, err | |
} | |
return data, nil | |
} | |
func main() { | |
data, err := readBootBlock() | |
if err != nil { | |
log.Fatalln(err) | |
} | |
var h Header | |
br := binary.BinaryReader{Reader: bytes.NewReader(data), Endianess: binary.LittleEndian} | |
br.ReadInterface(&h) | |
fmt.Printf("boot header: %+#v\n", h) | |
fmt.Printf("boot header: %+v\n", h) | |
// TODO: should probably read the data in 0x0 -> 0x30 | |
// to derive these values rather than have | |
// them hardcoded. | |
keyBytes := leswap(data[0x94 : 0x94+256]) | |
sig := leswap(data[h.SignatureLocation : h.SignatureLocation+256]) | |
var key rsa.PublicKey | |
key.E = *(*int)(unsafe.Pointer(&data[0x94+256])) | |
key.N = big.NewInt(0) | |
key.N.SetBytes(keyBytes) | |
copy(data[0x80:], data[h.BodyLocation:]) | |
hash := sha256.New() | |
io.Copy(hash, bytes.NewReader(data[:0xfb00])) | |
fmt.Println("Key:", key) | |
ha := hash.Sum(nil) | |
fmt.Printf("bootblock header:\n%s\nsha256 hash:\n%s\nsignature:\n%s\nkey:\n%s\n", hex.Dump(data[:0x80]), hex.Dump(ha), hex.Dump(sig), hex.Dump(keyBytes)) | |
if rsa.VerifyPKCS1v15(&key, crypto.SHA256, ha, sig) == nil { | |
log.Println("Verification success!") | |
} else { | |
log.Println("Verification error") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment