mirror of
https://github.com/Xpl0itU/WiiUDownloader.git
synced 2025-05-28 22:16:04 -04:00
Unfinished work
This commit is contained in:
commit
0a319d80d8
21 changed files with 3257 additions and 0 deletions
139
downloader.go
Normal file
139
downloader.go
Normal file
|
@ -0,0 +1,139 @@
|
|||
package wiiudownloader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/cavaliergopher/grab/v3"
|
||||
)
|
||||
|
||||
func downloadFile(client *grab.Client, url string, outputPath string) error {
|
||||
req, err := grab.NewRequest(outputPath, url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp := client.Do(req)
|
||||
if err := resp.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("[Info] Download saved to ./%v \n", resp.Filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func DownloadTitle(titleID string, outputDirectory string, doDecryption bool) error {
|
||||
outputDir := strings.TrimRight(outputDirectory, "/\\")
|
||||
baseURL := fmt.Sprintf("http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/%s", titleID)
|
||||
titleKeyBytes, err := hex.DecodeString(titleID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := grab.NewClient()
|
||||
downloadURL := fmt.Sprintf("%s/%s", baseURL, "tmd")
|
||||
tmdPath := filepath.Join(outputDir, "title.tmd")
|
||||
if err := downloadFile(client, downloadURL, tmdPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmdData, err := os.ReadFile(tmdPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var titleVersion uint16
|
||||
if err := binary.Read(bytes.NewReader(tmdData[476:478]), binary.BigEndian, &titleVersion); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tikPath := filepath.Join(outputDir, "title.tik")
|
||||
downloadURL = fmt.Sprintf("%s/%s", baseURL, "cetk")
|
||||
if err := downloadFile(client, downloadURL, tikPath); err != nil {
|
||||
return err
|
||||
}
|
||||
tikData, err := os.ReadFile(tikPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encryptedTitleKey := tikData[0x1BF : 0x1BF+0x10]
|
||||
|
||||
var contentCount uint16
|
||||
if err := binary.Read(bytes.NewReader(tmdData[478:480]), binary.BigEndian, &contentCount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cert := bytes.Buffer{}
|
||||
|
||||
cert0, err := getCert(tmdData, 0, contentCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cert.Write(cert0)
|
||||
|
||||
cert1, err := getCert(tmdData, 1, contentCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cert.Write(cert1)
|
||||
|
||||
defaultCert, err := getDefaultCert(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cert.Write(defaultCert)
|
||||
|
||||
certPath := filepath.Join(outputDir, "title.cert")
|
||||
certFile, err := os.Create(certPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(certFile, binary.BigEndian, cert.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
defer certFile.Close()
|
||||
fmt.Printf("[Info] Certificate saved to ./%v \n", certPath)
|
||||
|
||||
for i := 0; i < int(contentCount); i++ {
|
||||
offset := 2820 + (48 * i)
|
||||
var id uint32
|
||||
if err := binary.Read(bytes.NewReader(tmdData[offset:offset+4]), binary.BigEndian, &id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
appPath := filepath.Join(outputDir, fmt.Sprintf("%08X.app", id))
|
||||
downloadURL = fmt.Sprintf("%s/%08X", baseURL, id)
|
||||
if err := downloadFile(client, downloadURL, appPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tmdData[offset+7]&0x2 == 2 {
|
||||
h3Path := filepath.Join(outputDir, fmt.Sprintf("%08X.h3", id))
|
||||
downloadURL = fmt.Sprintf("%s/%08X.h3", baseURL, id)
|
||||
if err := downloadFile(client, downloadURL, h3Path); err != nil {
|
||||
return err
|
||||
}
|
||||
var content contentInfo
|
||||
content.Hash = tmdData[offset+16 : offset+0x14]
|
||||
content.ID = fmt.Sprintf("%08X", id)
|
||||
binary.Read(bytes.NewReader(tmdData[offset+8:offset+15]), binary.BigEndian, &content.Size)
|
||||
if err := checkContentHashes(outputDirectory, encryptedTitleKey, titleKeyBytes, content); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if doDecryption {
|
||||
decryptContents(outputDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue