Initial commit

This commit is contained in:
Garhoogin 2025-02-08 21:02:41 -06:00
commit 92f609bf88
26 changed files with 4988 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
build.bat
*.exe
*.bin
*.d
*.nds
*.elf
*.srl
*.map
*.o

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
BSD 2-Clause License
Copyright (c) 2025, Garhoogin
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# fwutil
Operate on DS firmware.

309
src/blowfish.c Normal file
View File

@ -0,0 +1,309 @@
#include "blowfish.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
static const BfBlowfishContext sInitTable = {
{
0x5f20d599, 0xb9f54457, 0xd9a4196e, 0x945a6a9e, 0xebf1aed8, 0x3ae27541, 0x32d08293, 0xd531ee33,
0x9a6157cc, 0x1ba20637, 0xf5723979, 0xbef6ae55, 0xfb691b5f, 0xe9f19de5, 0xa1d92cce, 0xe605325e,
0xcffed3fe, 0x0d0462d4
},
{
{
0xb7ecf58b, 0xbb79602b, 0x0d319512, 0x2bda3f6e, 0xf1f08488, 0x257e123d, 0xbbf12245, 0x061a0624,
0x28dfad11, 0x3481648b, 0x2933eb2b, 0xbdf2aa99, 0x9d95149c, 0x8cf5f79f, 0x29a19772, 0xcf5fd19d,
0x1a074d66, 0x4b4ad3de, 0xa3a7c985, 0x3a059517, 0xbf0a493d, 0xa28b890a, 0xdd49824a, 0x0bf19027,
0x6a1cebe9, 0x05457683, 0x617081ba, 0xde4b3f17, 0x39abcfae, 0x563af257, 0x8aad1148, 0x3f45e140,
0x54029bfa, 0xfb93a6ca, 0x6ffe4def, 0x9c87d8a3, 0x48d5ba08, 0xfd2d8d6a, 0x74f8156e, 0x8b52bebd,
0x9e8a2218, 0x073774fb, 0x4a6c361b, 0x6242ba19, 0x109179b9, 0x9665677b, 0xe82302fe, 0x778c99ee,
0x64865c3e, 0x86786d4d, 0xe2654fa5, 0x5adfb21e, 0x087ed00a, 0xac71b014, 0x1c83dbbd, 0x62a1d7b9,
0x7c63c6cd, 0xe6c36952, 0x12ce75bf, 0x04215d44, 0x3cd3fbfa, 0xd4631138, 0x49418595, 0x08f20946,
0x1fdc1143, 0x6d15c076, 0x70633c1f, 0x6c8087ea, 0x8b63bdc3, 0x372137c2, 0x2309eedc, 0x4d6a372e,
0x50f79073, 0x921cac30, 0x91231004, 0xaa07d24f, 0x9a4f3e68, 0x6a6064c9, 0xf32114c8, 0x124122d6,
0xe6cf2444, 0x0ddd568a, 0x85e14d53, 0x5a528c1e, 0xc284199c, 0x6ff15703, 0x58be00e3, 0xd5ed4cf6,
0x1f9c6421, 0x3c0355be, 0xaaffdc4a, 0x5de0dac9, 0xdee6bf5e, 0xf8b1d8f5, 0xb9b336ff, 0xdb956762,
0xed375f31, 0x9967704c, 0x3118b590, 0x99993d6c, 0xd3da42e4, 0xa0134225, 0x6c70d7ae, 0xc7cf55b1,
0x43d546d7, 0x443d1761, 0x8533e928, 0x93a2d0d5, 0x1f1225aa, 0x460bc5fb, 0x567697f5, 0x87bea645,
0xe86b94b1, 0x9933feb1, 0x6c3e1fae, 0x091d7139, 0xe4379000, 0x74753e10, 0x3b838cff, 0xf9b0f1b0,
0x42470501, 0xacd6f195, 0x9ee6387e, 0x3f267495, 0x185068b4, 0xb43043d0, 0x68e34b4c, 0xb64de5bf,
0xa00a8b95, 0x77322574, 0x2cf7a1cf, 0x5a1371d8, 0x51c9eaab, 0xefee0de8, 0x197e93e9, 0x38431ea7,
0xa12c1681, 0xcc73e348, 0xd36c2129, 0xd9a0ce5d, 0xa0437161, 0x64b51315, 0x192acf92, 0xa5b7addc,
0xf865869f, 0xfbe79f1a, 0x13b8fdf7, 0x6fdb276c, 0xf71c35df, 0x9b5b2c8d, 0x6438ab12, 0x31decc06,
0x11754ee8, 0xeafae364, 0xc25434eb, 0xeb343fad, 0x267d2c93, 0xf3569d36, 0xb3f6e15a, 0x9e4a6398,
0x9ae48332, 0x907d6084, 0xee0e132e, 0xa2364b93, 0x3816ec85, 0x020688e8, 0x3aa0f0bf, 0x9a6ad7ed,
0xcf57e173, 0xdcb844f8, 0xd159232e, 0x715295df, 0x4ba06199, 0x786e7fd5, 0x30c5a9ba, 0x328640d3,
0x9c0c329d, 0x2f02b737, 0xa99854ba, 0xc90413c4, 0xe7c8be8d, 0x2e50975d, 0x5922d693, 0x22bc270c,
0x20a7e092, 0x7f6f930f, 0xb5d39f4c, 0x740b2aa6, 0x107d4967, 0xc5d1cb26, 0x8ce77186, 0x5be99ca0,
0x01f61ab2, 0x5e9e8cee, 0xdb1af283, 0x84eae5e6, 0x7cd27659, 0x49a58df6, 0x16c24836, 0xa383bb52,
0x0c07b974, 0x2861ff3b, 0xe4e961e1, 0xaa156eef, 0x5de8ba4e, 0x32bb9605, 0x72fbb056, 0xc80e0f52,
0x76652542, 0xdef2af89, 0x01f02710, 0x97a7744b, 0x5426d507, 0x821f0954, 0x307d860a, 0x26b30e39,
0xbb570b9b, 0xaf310636, 0xd9fc79fd, 0x0c2b1030, 0xd79be1b3, 0xef5fdc7b, 0x4513f8d2, 0xbd75474d,
0x7e3c9646, 0xb53ef375, 0x3b9ac567, 0x6b295bb0, 0xc85b80de, 0x31b10515, 0xdd49ceb6, 0xaeb584ad,
0x3167dc60, 0x4efe3034, 0xa62f80bd, 0x213963bf, 0x7f35d986, 0x05226816, 0x2690e954, 0x516c078c,
0xd75531a4, 0x3ea80709, 0xc166532e, 0xc47bf2f8, 0xf1cf58f2, 0xe7a2c587, 0x87308f27, 0x6264a058,
0x88b91823, 0xc4cefa7c, 0x17adae98, 0xf35b4acc, 0x56d548e9, 0xc8f20dd3, 0xdb8c7392, 0xac562fd7
}, {
0x6992f981, 0xf632c64d, 0x218dc0e6, 0x618076e2, 0x6cdcbc11, 0x6919af93, 0xb9bfd09b, 0x67029f31,
0x83ee51a3, 0x0c7b2206, 0x404249ab, 0x7d01d5b8, 0x55f75ece, 0x99c53953, 0x9f87d846, 0xb464f7ba,
0xa1fa9ae3, 0x1068906d, 0x548aca30, 0xc3609fa7, 0x0d6bf519, 0xe698517a, 0xb4514398, 0x4fe935d6,
0x7b0fdfc3, 0xbd5c2fd6, 0x1961153a, 0xaacb4bf1, 0xc9646ddc, 0x561ec6d3, 0x504c38ef, 0xcc758671,
0xe94e0d0d, 0x5d06f628, 0xd3aa1b70, 0x39a8cf45, 0x2ea695ac, 0xd422e4b4, 0x5f37a874, 0xcc047a48,
0xd8404ca5, 0x0828b428, 0x52721c0d, 0x477df041, 0x4e533a19, 0x6b628458, 0x818ab593, 0xdc0d4e21,
0xc6a23fb4, 0x402bc9fc, 0xe90438da, 0x6b865a5e, 0x8525220c, 0x7c8d1168, 0x55951d92, 0xbb8eab4d,
0xb7e6a6da, 0x5a32b651, 0x05dd4105, 0x50560a2a, 0xcc471791, 0xb57ee6c9, 0x73db4a61, 0x33c85167,
0x746edaf5, 0x37c3542e, 0x08af6d0d, 0x5f8a15e8, 0xcd2159e2, 0x060cdea8, 0x5f6b775a, 0x3e6518db,
0x78de50c8, 0xb382b8e0, 0x32724e5d, 0x34c14f07, 0xb796ba23, 0x28a44e67, 0xeb62341e, 0xe9706a2d,
0x70c4422f, 0x9c315a4e, 0x28475bf9, 0x6f71daaa, 0x78b31f38, 0x1c6b92c4, 0x9a35f69e, 0xbf0e4db7,
0x412918cc, 0x5d354803, 0xc62bd055, 0x605caf29, 0x5e8e6974, 0xbdd47c9b, 0x7d64447b, 0x695d923f,
0x4b001fb6, 0xcf3583d4, 0x174e647e, 0x2ed58dae, 0x4e12289a, 0x08492b2e, 0x46c6ae5c, 0x6141ae85,
0xd2826f1e, 0x1f163751, 0xa459f60b, 0xaf5aca9a, 0x8b33d40d, 0x84f16320, 0xcfcb5c80, 0xd3b9b408,
0x62bd0516, 0x569b3183, 0xba9f9851, 0xb2aa5bb2, 0xb52c6b22, 0x63fa48d4, 0xfa585f2b, 0x0964fa61,
0xb8e038bb, 0xa860929d, 0x0e6f670d, 0x010df537, 0xd477c29f, 0x73f1ecfe, 0x7de03930, 0xe49861f5,
0x0455282c, 0x2fdb5556, 0x58e5ec6b, 0x8064b606, 0x4e1a2a6a, 0xc4d80f5b, 0x19522e0a, 0x30f562d9,
0x7b8cbe48, 0xa29b384f, 0xd3c9afc3, 0x4162c1c7, 0x2161b986, 0x4f996f57, 0x7bcebac1, 0x5e4d3bb5,
0x57448b8a, 0x705f135f, 0x47295b6d, 0xece238dc, 0x12655504, 0x4317e82a, 0x2add8ee1, 0xf794e2b3,
0xe65c6e09, 0x6df88aeb, 0x48544989, 0xbfad2ff5, 0xca4b94ea, 0x828739fc, 0xf2018a5f, 0x71e6f275,
0xde42d8d6, 0x281d2df1, 0xa37e88a6, 0x301d47a0, 0xdf71a3d9, 0x01cb1c49, 0xf2b136f8, 0x5d5822f0,
0xa0bd6b45, 0x4288b2bb, 0xce288cc7, 0x6390e893, 0x897c9008, 0xb77df53c, 0x554f2d04, 0x7efd1651,
0xc1bee879, 0xf8d412f2, 0x230584b4, 0x2bd2cca0, 0xadabe1fd, 0x6c55d10d, 0x4d944123, 0x054f3777,
0x17bf0c28, 0x6c6712b3, 0xf75ac38c, 0x6d2a8441, 0x271294d0, 0x9cedb42c, 0x8247ec4d, 0xb967d597,
0x55c09d1b, 0x8ee57e07, 0x3ee7a8e2, 0x3a0ee412, 0x3455452a, 0x5a2df9a2, 0x7c52ab1b, 0x555f1083,
0x435af1d2, 0xa4a7c62b, 0xe8951589, 0xf89d4bb4, 0x609fe375, 0xe6d65b78, 0x21e6440d, 0x2247bd06,
0xad00a453, 0x8513438d, 0xfcaaf739, 0xed7baf38, 0x542be4fc, 0xfc4c9850, 0xdff78085, 0xe122803c,
0x24deda94, 0x397ab0c6, 0xa10fdc38, 0x6ff9f4a7, 0x8b571863, 0x2e2a4184, 0xd9f253d4, 0xddd00f00,
0xa6196e99, 0x5becd00a, 0xc0ab2458, 0xec6506cb, 0x9438131a, 0x2f03670a, 0x77e3f73f, 0xc6337744,
0xe3d03914, 0x7908a2c0, 0x579940bb, 0x90010b41, 0x48cce1cd, 0xafb3db67, 0x4cf37488, 0xb1728f82,
0xc42923b5, 0xfc196c12, 0x9ca4468e, 0x876525c4, 0x8abe6dd3, 0x38031193, 0xf32b83ed, 0xea93a446,
0x1d85533b, 0x08f1d4ce, 0xfced2783, 0xbc181a9b, 0xdcae8bf9, 0x3850ab24, 0x104b72e9, 0x467b1722
}, {
0x6459ab5d, 0xf8ae40f3, 0xf9c8e5bb, 0x554e0326, 0xfeebeb7d, 0xe0e639f7, 0x2ebe110a, 0xed98ff28,
0x5642c9c0, 0x00fdc342, 0xa287aff6, 0x323f015b, 0x9a954792, 0x3d32a572, 0x9bd06bae, 0x9249d207,
0xfa4a78e3, 0xf27d06a1, 0x7477cf41, 0x0cb21404, 0x16648486, 0xa151bbd5, 0xd1f16fe5, 0x5ff7e2f2,
0xb84d2058, 0xddcfc757, 0x76bed8c5, 0x7e5ff63d, 0x888b2ae7, 0x3f381b24, 0x7723410e, 0xd44bf0f5,
0xa4fa1f0c, 0xcf5f800b, 0xdae0f645, 0x5359342f, 0x523c20fb, 0xb5355e62, 0x608bfe62, 0x5a86e363,
0xd16e1a15, 0x32bc4547, 0x3867ebb4, 0x336ee4ab, 0xa3edb53a, 0x4ee067ad, 0x62ee9541, 0x1d267162,
0x3062ef31, 0xac82d7af, 0x0405dcc2, 0xbf0797f5, 0x07235911, 0xe80264c0, 0xaf3ee597, 0xa659ac18,
0x90334a8b, 0x9c7c6e1c, 0x3c4c7e20, 0xbb64613e, 0x7e7c6bc5, 0x4cc59f3e, 0xf573ea9f, 0x4cc089d7,
0x2df4fbf4, 0x511b14ec, 0xc812c1d5, 0x4a0bdf10, 0x93bc9c8b, 0x3e3e6a45, 0xbaa9c17d, 0x07b4c1cd,
0x8668e1e4, 0x386db243, 0x5c0cfbf3, 0xde713766, 0xa06eef56, 0xa7654010, 0xbed0f798, 0x3637c80e,
0x7cca10ec, 0x1e84ab9c, 0x02761705, 0xaa524f1c, 0xa0c6c15f, 0x04d8b956, 0xa74d4484, 0x60ded859,
0x050e38e6, 0x3be1038f, 0x3304816d, 0xce0b306f, 0x33210569, 0x89bb26fb, 0x87aeb67d, 0xe007517e,
0x0a96f7ac, 0x5cc4f96b, 0x4744e41d, 0xe3fa5eb8, 0x42558478, 0xf75e484b, 0x8635477d, 0x05432b1d,
0xb88aec03, 0x763c061e, 0x431a480c, 0xed8ab7a7, 0x43c6131e, 0xdbef10ee, 0x833cfbec, 0xef4495b2,
0x4e5154d8, 0x1d44112d, 0x1e5936fb, 0xc3c1347a, 0x610057ca, 0x16a567ea, 0x55d0559b, 0x36d97fe1,
0xae7640d2, 0xb0ce01dc, 0xcbd5837a, 0x6bec9820, 0x349272c1, 0x375782f3, 0x36328a62, 0xae43900c,
0x789b5cae, 0x0265138e, 0xc17168fd, 0xa031b0fe, 0xc3b08224, 0xa76979b1, 0xd0ebd2f5, 0xdc32c082,
0x3c26c79e, 0xc1988d6d, 0xd0d422bb, 0x3eec330f, 0xdce1ccb9, 0x36774c6a, 0xbff91c14, 0x5f289f81,
0x29328571, 0xc4487590, 0xd8ce4ab3, 0x2f148f44, 0xef5740fd, 0xd97508aa, 0x6ed6d146, 0xc31f5532,
0x1f84fe18, 0xffd584fc, 0x481b5e71, 0x0e9586c3, 0xd3270828, 0x7b718338, 0x5463804c, 0xacb0569a,
0x31ca80cf, 0xf3feef09, 0x7e24afbe, 0x3f53fea6, 0x334a8dc2, 0xa622d168, 0xea7bad66, 0xb043b6de,
0x009525a1, 0x46753fa3, 0xec441114, 0x92bc95d7, 0x16a94ff0, 0x60976253, 0xf1410f2a, 0xeebe2471,
0xcd087f94, 0x85b39360, 0x3f00075b, 0x83280fd8, 0x9f69d19a, 0xc32edad1, 0xb9a20190, 0x662a4e6b,
0xa6aeda9d, 0x68d32aea, 0x9c0c0c2f, 0xed4a8cd2, 0x65579ee2, 0xa387099d, 0x5d32c4b4, 0x2b32d4c9,
0x1e71e0b1, 0x90e64d64, 0x401ee371, 0x84f37ded, 0x78c8ed0e, 0x71c0ae76, 0x05bb7227, 0xfb6402ea,
0xb56b48f3, 0xed3f9342, 0xd253139f, 0xec2afef7, 0xdb25471d, 0xc686913c, 0xfd11f08e, 0xf7367423,
0x7a9ef5a4, 0x4450537e, 0xd3ca47d4, 0xe66d38eb, 0x7f9471d9, 0x4b69c64a, 0xea52f411, 0xb08afe22,
0x598b6736, 0x2a80e6e8, 0x130465eb, 0x9edcecee, 0x05ecb15f, 0x9fe6596a, 0x896b595e, 0xca1af7bf,
0x6a5bf944, 0xe4038571, 0x70e06229, 0xcfc4416f, 0xe3ccb1b2, 0xa807a67e, 0x847fe787, 0x4b52db93,
0xdd7eec6c, 0x104824d4, 0x60049f69, 0x1848e674, 0xb92ce4f3, 0x7a502e4f, 0x6954d4df, 0xf3a78b2b,
0xf31fffce, 0x3901263e, 0x89849517, 0x4b4cf0b0, 0xc49f9182, 0xa59dac4b, 0x2517af74, 0xd332cac9,
0x848a89bc, 0xae0dcc89, 0x9cdba27c, 0xee91786a, 0x4e5d76ea, 0x69f56087, 0x02d46715, 0x3648afcf
}, {
0x6fbfea07, 0x8f062d66, 0xf9fe9ac4, 0x758790f6, 0x0fadf7b8, 0x3d5a1076, 0xb32eb059, 0xcc2c35c7,
0xcb2b5670, 0xc59637e3, 0x8a1b462f, 0x88c74622, 0x983226a7, 0x2286df61, 0x2f1cf48a, 0xaa09a187,
0xd3aea9cc, 0x1c4500bd, 0x8687549a, 0xffef8752, 0x8fa18f1e, 0x355c89c1, 0x3a2dda1b, 0xc2b2162c,
0x78e256f1, 0x97636bc1, 0xc98f56c5, 0xaa2c7f32, 0xaca8a6af, 0x88229120, 0x8b60e4de, 0x25424bf9,
0x9c7fe31a, 0x3a89192c, 0x36d4057e, 0xc25869cc, 0x2f8b32c1, 0x7aeb8590, 0xa1a55039, 0x66c59227,
0x584f20b0, 0x4383557e, 0x9ce2452b, 0x9012d8e4, 0x5683162c, 0xb3037916, 0x18612dad, 0x371f131a,
0x739ce1e2, 0xfdd5807b, 0xfc87512d, 0x1fd7aa7b, 0xaf8e7a2c, 0xcdbb8df4, 0x727c1195, 0xe26fee0b,
0x37deafb9, 0x8d8cde83, 0xb7670562, 0x568dc696, 0x62d70db6, 0x3646d6ba, 0xe6c88ebd, 0x106c2aea,
0x5b6bff14, 0x463c82fa, 0x464330b1, 0x9b7d8a51, 0x79833e92, 0xb25d555b, 0x90ce5e6c, 0x98538e62,
0xe56d0dc9, 0xc5cd572d, 0xe1ba5781, 0x728fb8e8, 0xdc134fe5, 0x15719dea, 0x8811b210, 0x7fd409d5,
0x2c7f655b, 0x114c383b, 0xfb8d5068, 0xbf59b09e, 0x4a898094, 0x12181ac5, 0x4ad15389, 0x8ce82910,
0xeab6ec1c, 0x8b17c746, 0xa8311525, 0xb1436ba2, 0x0bdbe29d, 0x11b09b87, 0xd2710e04, 0x82897729,
0x7f41660a, 0xff480b1d, 0xfd24bb72, 0x9ba148c2, 0xce7f7bfe, 0xd986db88, 0xb01c3b85, 0x0733a8dc,
0xe32e51bf, 0x97009a0e, 0x97c0061e, 0xb6d89d43, 0x6786c445, 0x88f8005f, 0x9e52a49a, 0x838aaac7,
0x18c5ec75, 0x2fc3ceae, 0x18f92b1a, 0xf51aaeff, 0x33b50b53, 0xe8fda751, 0x64a2e1a8, 0x431722b6,
0xd80acc80, 0x40ba3bae, 0x4a92d9d7, 0x1004df89, 0x2b189bee, 0x8a69776a, 0xb9f9f468, 0x6e1521a2,
0x033b1ee6, 0x609b3062, 0x9b257e41, 0x52c58f9e, 0xc2f80810, 0x1121a169, 0x795e3788, 0x10ff6635,
0xed6e1842, 0x1c6bb697, 0x6de5364e, 0xbfe4b47d, 0x05e0b920, 0xb8d5693a, 0xe0dcd5e3, 0x3e53acb9,
0xad57a407, 0x1848ff77, 0x49ac2a76, 0x75478e2a, 0x63679f6d, 0x398c3530, 0x6fd53905, 0xad5b3a64,
0x82bb0bca, 0xb1459952, 0x99363693, 0x442013af, 0x4402d836, 0x85923909, 0x974a4aff, 0xd763a687,
0x24b5b5c7, 0x6fb40fed, 0x1452580c, 0xd37ba6d9, 0x5838bc79, 0x843bbda1, 0x061ad806, 0xeaa86bfd,
0x0428694b, 0x9982ad37, 0x851b0efb, 0x735da8bd, 0x7558dccd, 0x6c63be0a, 0xe44ce748, 0x60042b30,
0xdad815b9, 0x8f758186, 0x1c8dd496, 0x7c85705d, 0xd57b671c, 0xcea66708, 0x70660a4b, 0xd463e5b7,
0xea828a5b, 0xe2ca6710, 0x8517eff4, 0x8a5f2a2f, 0x6af88297, 0xea1034d6, 0x3c5cc9eb, 0x46f849e1,
0xf6bddeeb, 0xaaf192a9, 0xb018a0a6, 0x1f0fd33a, 0x31ff6ff3, 0xd3444345, 0x88f79a50, 0xcec19609,
0x2cf2cc76, 0x82adba2c, 0x84188f77, 0x9c07d2c0, 0x4e839036, 0x434fa50b, 0x78ab043e, 0x09fbd64f,
0xda902401, 0x613a3c6f, 0x4a697f0d, 0x02302beb, 0x84e0dbb4, 0x35d7eca9, 0x857d37bf, 0x4ea9ce58,
0xa8c780e4, 0x486730d3, 0x2faf29eb, 0xa7b46a74, 0x923f0f3f, 0xaccaf3af, 0x94d94baf, 0x81ca43c0,
0xa1482f0d, 0xd2d527b0, 0x85054bef, 0x934ddea3, 0xbbf03c30, 0x27308f4a, 0x3ee3eb4c, 0x2f9aed64,
0xf082f13b, 0x7fcff4ba, 0xe1b0cb40, 0x57aabc7f, 0xf274c9d3, 0x220d43fa, 0x4e77f4d0, 0x7085d793,
0xb6bf991f, 0x30f135de, 0xf0715ea7, 0x7b2d016b, 0x5333f064, 0xf388390a, 0x6ba63a6b, 0x432fd235,
0xb5fd02cd, 0xaa5bbce9, 0x7e19a4d8, 0x81945d0e, 0xad776f9e, 0x93740ed6, 0x18c4e796, 0x19f5ad5f
}
}
};
static void SwapInts(uint32_t *p1, uint32_t *p2) {
uint32_t temp = *p1;
*p1 = *p2;
*p2 = temp;
}
static uint32_t F(BfBlowfishContext *ctx, uint32_t x) {
uint32_t y = 0;
y ^= ctx->sbox[0][(x >> 24) & 0xFF];
y += ctx->sbox[1][(x >> 16) & 0xFF];
y ^= ctx->sbox[2][(x >> 8) & 0xFF];
y += ctx->sbox[3][(x >> 0) & 0xFF];
return y;
}
static void BfEncryptBlock(BfBlowfishContext *ctx, uint32_t *xl, uint32_t *xr) {
uint32_t Xl = *xl;
uint32_t Xr = *xr;
for (int i = 0; i < 16; i++) {
Xl ^= ctx->parr[i];
Xr ^= F(ctx, Xl);
SwapInts(&Xl, &Xr);
}
*xl = Xr ^ ctx->parr[17];
*xr = Xl ^ ctx->parr[16];
}
static void BfDecryptBlock(BfBlowfishContext *ctx, uint32_t *xl, uint32_t *xr) {
uint32_t Xl = *xl;
uint32_t Xr = *xr;
for (int i = 17; i > 1; i--) {
Xl ^= ctx->parr[i];
Xr ^= F(ctx, Xl);
SwapInts(&Xl, &Xr);
}
*xl = Xr ^ ctx->parr[0];
*xr = Xl ^ ctx->parr[1];
}
void BfCtxInit(BfBlowfishContext *ctx, const unsigned char *key, unsigned int keylen) {
unsigned int k = 0;
for (int i = 0; i < 18; i++) {
ctx->parr[i] ^= key[(k++) % keylen] << 24;
ctx->parr[i] ^= key[(k++) % keylen] << 16;
ctx->parr[i] ^= key[(k++) % keylen] << 8;
ctx->parr[i] ^= key[(k++) % keylen] << 0;
}
uint32_t l = 0, r = 0;
for (int i = 0; i < 9; i++) {
BfEncryptBlock(ctx, &l, &r);
ctx->parr[i * 2 + 0] = l;
ctx->parr[i * 2 + 1] = r;
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 128; j++) {
BfEncryptBlock(ctx, &l, &r);
ctx->sbox[i][j * 2 + 0] = l;
ctx->sbox[i][j * 2 + 1] = r;
}
}
}
static void BfCtxMixKey(BfBlowfishContext *ctx, uint32_t *keyBufp, uint32_t keylen) {
BfEncryptBlock(ctx, keyBufp + 2, keyBufp + 1);
BfEncryptBlock(ctx, keyBufp + 1, keyBufp + 0);
BfCtxInit(ctx, (unsigned char *) keyBufp, keylen);
}
static void BfCtxInitWithKey(BfBlowfishContext *ctx, uint32_t key, const unsigned char *fwHeader) {
memcpy(ctx, &sInitTable, sizeof(BfBlowfishContext));
uint32_t keyBufp[3];
keyBufp[0] = key;
keyBufp[1] = key >> 1;
keyBufp[2] = key << 1;
BfCtxMixKey(ctx, keyBufp, 12);
const uint32_t *blowfishedKeyp = (const uint32_t *) (fwHeader + 0x18);
uint32_t keycpy[2];
memcpy(keycpy, blowfishedKeyp, sizeof(keycpy));
BfDecryptBlock(ctx, keycpy + 1, keycpy + 0);
BfCtxMixKey(ctx, keyBufp, 12);
}
void BfDecrypt(unsigned char *buf, unsigned int len, const unsigned char *fwHeader) {
//init blowfish
BfBlowfishContext ctx;
BfCtxInitWithKey(&ctx, *(const uint32_t *) (fwHeader + 0x8), fwHeader);
for (unsigned int i = 0; i < len / 8; i++) {
uint32_t *p = (uint32_t *) (buf + i * 8);
BfDecryptBlock(&ctx, p + 1, p + 0);
}
}
void BfEncrypt(unsigned char *buf, unsigned int len, const unsigned char *fwHeader) {
//init blowfish
BfBlowfishContext ctx;
BfCtxInitWithKey(&ctx, *(const uint32_t *) (fwHeader + 0x8), fwHeader);
for (unsigned int i = 0; i < len / 8; i++) {
uint32_t *p = (uint32_t *) (buf + i * 8);
BfEncryptBlock(&ctx, p + 1, p + 0);
}
}
BfStream *BfDecryptStreamInit(const unsigned char *buffer, unsigned int len, const unsigned char *fwHeader) {
BfStream *stream = (BfStream *) calloc(1, sizeof(BfStream));
stream->buffer = buffer;
stream->size = len;
stream->srcpos = 0;
stream->error = 0;
BfCtxInitWithKey(&stream->ctx, *(const uint32_t *) (fwHeader + 0x8), fwHeader);
return stream;
}
unsigned char BfDecryptStreamNext(BfStream *stream) {
unsigned int blockpos = stream->srcpos & 7;
if (blockpos == 0) {
//check bounds on next fetch
if ((stream->size - stream->srcpos) < 8) {
stream->error = 1;
return 0xFF;
}
//blockpos==0: fetch next block
stream->block[0] = (stream->buffer[stream->srcpos + 0] << 0)
| (stream->buffer[stream->srcpos + 1] << 8)
| (stream->buffer[stream->srcpos + 2] << 16)
| (stream->buffer[stream->srcpos + 3] << 24);
stream->block[1] = (stream->buffer[stream->srcpos + 4] << 0)
| (stream->buffer[stream->srcpos + 5] << 8)
| (stream->buffer[stream->srcpos + 6] << 16)
| (stream->buffer[stream->srcpos + 7] << 24);
BfDecryptBlock(&stream->ctx, stream->block + 1, stream->block + 0);
}
stream->srcpos++;
return (stream->block[blockpos / 4] >> ((blockpos & 3) * 8)) & 0xFF;
}
void BfDecryptStreamEnd(BfStream *stream) {
//nothing
free(stream);
}

24
src/blowfish.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
typedef struct BlowfishCtx_ {
unsigned int parr[18];
unsigned int sbox[4][256];
} BfBlowfishContext;
typedef struct BfStream_ {
BfBlowfishContext ctx;
const unsigned char *buffer;
unsigned int size;
unsigned int srcpos;
uint32_t block[2];
int error;
} BfStream;
void BfDecrypt(unsigned char *buf, unsigned int len, const unsigned char *fwHeader);
void BfEncrypt(unsigned char *buf, unsigned int len, const unsigned char *fwHeader);
BfStream *BfDecryptStreamInit(const unsigned char *buffer, unsigned int len, const unsigned char *fwHeader);
unsigned char BfDecryptStreamNext(BfStream *stream);
void BfDecryptStreamEnd(BfStream *stream);

252
src/cmd_clean.c Normal file
View File

@ -0,0 +1,252 @@
#include "cmd_common.h"
#include "firmware.h"
#include <string.h>
#include <ctype.h>
//simple file format for backing up user config data from a firmware image
typedef struct FirmwareSettings_ {
uint16_t wlTableSize; // size of wireless table
unsigned char wlTable[512]; // wireless initialization table
uint16_t connSettingSize; // size of connection settings
unsigned char connSetting[0x400]; // connection settings
uint16_t connExSettingSize; // size of extra connection settings
unsigned char connExSetting[0x600]; // extended connection settings
uint16_t userConfigSize; // size of user configg
unsigned char userConfig[0x200]; // user config
} FirmwareSettings;
void CmdHelpClean(void) {
puts("");
puts("Usage: clean");
puts("");
puts("Cleans the firmware image of the wireless initialization tables, user config,");
puts("and wireless connection settings. The cleaned information can optionally be");
puts("written to a file to restore later.");
}
void CmdProcClean(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
FlashHeader *hdr = (FlashHeader *) buffer;
char fname[1024];
printf("Save config path (enter to skip): ");
fgets(fname, sizeof(fname), stdin);
int len = strlen(fname);
for (int i = 0; i < len; i++) {
if (fname[i] == '\n' || fname[i] == '\r') {
fname[i] = '\0';
break;
}
}
//wireless table
unsigned char *wlTable = buffer + 0x2A;
unsigned int wlTableSize = 0x200 - 0x2A;
//user config
unsigned int ncdOffset = (hdr->nvramUserConfigAddr * 4) * 2;
unsigned char *ncd = NULL;
unsigned int ncdSize = 0;
if (ncdOffset < size && (ncdOffset + 0x200) <= size) {
ncd = buffer + ncdOffset;
ncdSize = 0x200;
}
//connection settings
unsigned char *connSettings = NULL;
unsigned int connSettingsSize = 0;
unsigned char *connExSettings = NULL;
unsigned int connExSettingsSize = 0;
if (ncdOffset >= 0x400 && ncd != NULL) {
connSettings = ncd - 0x400;
connSettingsSize = 0x400;
}
if (HasTwlSettings(hdr->ipl2Type) && ncdOffset >= 0xA00 && connSettings != NULL) {
connExSettings = connSettings - 0x600;
connExSettingsSize = 0x600;
}
if (fname[0] != '\0') {
//write
FILE *fp = fopen(fname, "wb");
if (fp != NULL) {
FirmwareSettings *settings = calloc(1, sizeof(FirmwareSettings));
settings->wlTableSize = wlTableSize;
settings->connSettingSize = connSettingsSize;
settings->connExSettingSize = connExSettingsSize;
settings->userConfigSize = ncdSize;
if (wlTable != NULL) memcpy(settings->wlTable, wlTable, wlTableSize);
if (connSettings != NULL) memcpy(settings->connSetting, connSettings, connSettingsSize);
if (connExSettings != NULL) memcpy(settings->connExSetting, connExSettings, connExSettingsSize);
if (ncd != NULL) memcpy(settings->userConfig, ncd, ncdSize);
fwrite(settings, sizeof(*settings), 1, fp);
fclose(fp);
free(settings);
}
}
//erase
if (wlTable != NULL) { memset(wlTable, 0xFF, wlTableSize ); printf("Erased wireless init table.\n"); }
if (connSettings != NULL) { memset(connSettings, 0xFF, connSettingsSize ); printf("Erased connection settings.\n"); }
if (connExSettings != NULL) { memset(connExSettings, 0xFF, connExSettingsSize); printf("Erased extra connection settings.\n"); }
if (ncd != NULL) {
for (int i = 0; i < 2; i++) {
FlashUserConfigData *ncdi = &((FlashUserConfigData *) ncd)[i];
memset(ncdi, 0, FLASH_NCD_SIZE + FLASH_NCD_EX_SIZE);
ncdi->saveCount = i & 0x7F;
ncdi->version = 5;
ncdi->crc = ComputeCrc(ncdi, FLASH_NCD_SIZE-4, 0xFFFF);
if (HasExConfig(hdr->ipl2Type)) {
int isKOR = (hdr->ipl2Type != IPL2_TYPE_NORMAL) && (hdr->ipl2Type & IPL2_TYPE_KOREAN);
int isCHN = (hdr->ipl2Type != IPL2_TYPE_NORMAL) && (hdr->ipl2Type & IPL2_TYPE_CHINESE);
int isUSG = (hdr->ipl2Type != IPL2_TYPE_NORMAL) && (hdr->ipl2Type & IPL2_TYPE_USG);
//Korean or Chinese USG: fill by FF
if (isKOR || (isCHN && !isUSG)) memset(&ncdi->exVersion, 0xFF, FLASH_NCD_EX_SIZE);
ncdi->exVersion = 1;
ncdi->exLanguage = 1; // default to English
//language mask:
//Korean: Korean, Spanish, German, French, English, Japanese
//Chinese: Chinese, Spanish, Italian, German, French, English
ncdi->languages = isKOR ? 0x00AF : 0x007E;
ncdi->exCrc = ComputeCrc(&ncdi->exVersion, FLASH_NCD_EX_SIZE-2, 0xFFFF);
} else {
//no ex config: zero only main buffer
memset(&ncdi->exVersion, 0xFF, FLASH_NCD_EX_SIZE);
}
}
printf("Erased user configuration.\n");
}
}
void CmdHelpRestore(void) {
puts("");
puts("Usage: restore <filename>");
puts("");
puts("Restores configuration information from a file written by the 'clean' command.");
puts("You wil be prompted whether to restore the wireless initialization, user");
puts("configuration information, and wireless connection settings.");
}
void CmdProcRestore(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
if (argc < 2) {
CmdHelpRestore();
return;
}
const char *fname = argv[1];
FILE *fp = fopen(fname, "rb");
if (fp == NULL) {
printf("Could not open '%s' for read access.\n", fname);
return;
}
unsigned int settingsSize;
fseek(fp, 0, SEEK_END);
settingsSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *settingsbuf = malloc(settingsSize);
fread(settingsbuf, settingsSize, 1, fp);
fclose(fp);
if (settingsSize != sizeof(FirmwareSettings)) {
printf("Invalid settings file.\n");
free(settingsbuf);
return;
}
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
FlashHeader *hdr = (FlashHeader *) buffer;
FirmwareSettings *settings = (FirmwareSettings *) settingsbuf;
//wireless table
unsigned char *wlTable = buffer + 0x2A;
unsigned int wlTableSize = 0x200 - 0x2A;
//user config
unsigned int ncdOffset = (hdr->nvramUserConfigAddr * 4) * 2;
unsigned char *ncd = NULL;
unsigned int ncdSize = 0;
if (ncdOffset < size && (ncdOffset + 0x200) <= size) {
ncd = buffer + ncdOffset;
ncdSize = 0x200;
}
//connection settings
unsigned char *connSettings = NULL;
unsigned int connSettingsSize = 0;
unsigned char *connExSettings = NULL;
unsigned int connExSettingsSize = 0;
if (ncdOffset >= 0x400 && ncd != NULL) {
connSettings = ncd - 0x400;
connSettingsSize = 0x400;
}
if (HasTwlSettings(hdr->ipl2Type) && ncdOffset >= 0xA00 && connSettings != NULL) {
connExSettings = connSettings - 0x600;
connExSettingsSize = 0x600;
}
char textbuffer[1024];
if (wlTable != NULL) {
printf("Restore wireless init table? (y/n) ");
fgets(textbuffer, sizeof(textbuffer), stdin);
if (toupper(textbuffer[0]) == 'Y') {
if (settings->wlTableSize < wlTableSize) wlTableSize = settings->wlTableSize;
memcpy(wlTable, settings->wlTable, wlTableSize);
}
}
if (ncd != NULL) {
printf("Restore user config? (y/n) ");
fgets(textbuffer, sizeof(textbuffer), stdin);
if (toupper(textbuffer[0]) == 'Y') {
if (settings->userConfigSize < ncdSize) ncdSize = settings->userConfigSize;
memcpy(ncd, settings->userConfig, settings->userConfigSize);
}
}
if (connSettings != NULL) {
printf("Restore connection settings? (y/n) ");
fgets(textbuffer, sizeof(textbuffer), stdin);
if (toupper(textbuffer[0]) == 'Y') {
if (settings->connSettingSize < connSettingsSize) connSettingsSize = settings->connSettingSize;
memcpy(connSettings, settings->connSetting, settings->connSettingSize);
}
}
if (connExSettings != NULL) {
printf("Restore extended connection settings? (y/n) ");
fgets(textbuffer, sizeof(textbuffer), stdin);
if (toupper(textbuffer[0]) == 'Y') {
if (settings->connExSettingSize < connExSettingsSize) connExSettingsSize = settings->connExSettingSize;
memcpy(connExSettings, settings->connExSetting, connExSettingsSize);
}
}
free(settingsbuf);
}

149
src/cmd_common.c Normal file
View File

@ -0,0 +1,149 @@
#include "cmd_common.h"
#include "firmware.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
static char *gFirmwarePath = NULL;
static unsigned char *gFirmware = NULL;
static unsigned int gFirmwareSize = 0;
static int gQuit = 0;
const char *GetCurrentFilePath(void) {
return gFirmwarePath;
}
unsigned char *GetFirmwareImage(unsigned int *pSize) {
*pSize = gFirmwareSize;
return gFirmware;
}
int LoadFirmwareImage(const char *path) {
FILE *fp = fopen(path, "rb");
if (fp == NULL) {
printf("Could not open file '%s' for read acces.\n", path);
return 0;
}
fseek(fp, 0, SEEK_END);
unsigned int size = ftell(fp);
fseek(fp, 0, SEEK_SET);
unsigned char *buf = malloc(size);
fread(buf, size, 1, fp);
fclose(fp);
if (size < (4 * 1024)) {
printf("Invalid firmware image size (%d bytes).\n", size);
free(buf);
return 0;
}
if (gFirmwarePath != NULL) {
free(gFirmwarePath);
}
if (gFirmware != NULL) {
free(gFirmware);
}
gFirmwarePath = strdup(path);
gFirmware = buf;
gFirmwareSize = size;
printf("Loaded %s.\n", gFirmwarePath);
return 1;
}
int RequireFirmwareImage(void) {
if (gFirmware == NULL) {
puts("No valid firmware image loaded.");
puts("Load a firmware image using the 'load' command.");
return 0;
}
return 1;
}
int IsExiting(void) {
return gQuit;
}
void DoExit(void) {
gQuit = 1;
}
uint32_t ParseArgNumber(const char *arg) {
if (*arg == '\0') return 0;
//parse number. Assume hexadecimal by default.
int radix = 16;
uint32_t val = 0;
if (gFirmware != NULL && gFirmwareSize >= 0x200 && arg[0] == '$') {
//pseudo-variable expansion
arg++;
FlashHeader *hdr = (FlashHeader *) gFirmware;
uint32_t arm9StaticRomAddr = (hdr->arm9StaticRomAddr * 4) << hdr->arm9RomAddrScale;
uint32_t arm7StaticRomAddr = (hdr->arm7StaticRomAddr * 4) << hdr->arm7RomAddrScale;
uint32_t arm9SecondaryRomAddr = (hdr->arm9SecondaryRomAddr * 4) * 2;
uint32_t arm7SecondaryRomAddr = (hdr->arm7SecondaryRomAddr * 4) * 2;
uint32_t rsrcRomAddr = (hdr->resourceRomAddr * 4) * 2;
uint32_t ncdaddr = (hdr->nvramUserConfigAddr * 4) * 2;
uint32_t connaddr = ncdaddr - 0x400;
uint32_t connexaddr = connaddr - 0x600;
if (stricmp(arg, "arm9") == 0) return arm9StaticRomAddr;
if (stricmp(arg, "arm7") == 0) return arm7StaticRomAddr;
if (stricmp(arg, "arm9s") == 0) return arm9SecondaryRomAddr;
if (stricmp(arg, "arm7s") == 0) return arm7SecondaryRomAddr;
if (stricmp(arg, "rsrc") == 0) return rsrcRomAddr;
if (stricmp(arg, "ncd") == 0) return ncdaddr;
if (stricmp(arg, "ncd0") == 0) return ncdaddr;
if (stricmp(arg, "ncd1") == 0) return ncdaddr + 0x100;
if (stricmp(arg, "conn") == 0) return connaddr;
if (stricmp(arg, "conn0") == 0) return connaddr + 0x000;
if (stricmp(arg, "conn1") == 0) return connaddr + 0x100;
if (stricmp(arg, "conn2") == 0) return connaddr + 0x200;
if (stricmp(arg, "connex") == 0) return connexaddr;
if (stricmp(arg, "connex0") == 0) return connexaddr + 0x000;
if (stricmp(arg, "connex1") == 0) return connexaddr + 0x200;
if (stricmp(arg, "connex2") == 0) return connexaddr + 0x400;
return val;
}
if (arg[0] == '0') {
if (arg[1] == 'x' || arg[1] == 'X') {
radix = 16; // hexadecimal
arg += 2;
} else if (arg[1] == 'n' || arg[1] == 'N') {
radix = 10; // decimal
arg += 2;
} else if (arg[1] == 'o' || arg[1] == 'O') {
radix = 8; // octal
arg += 2;
}
}
char c;
while ((c = *(arg++)) != '\0') {
int digit = -1;
if (c >= '0' && c <= '9') digit = (c - '0') + 0x0;
if (c >= 'A' && c <= 'F') digit = (c - 'A') + 0xA;
if (c >= 'a' && c <= 'f') digit = (c - 'a') + 0xA;
//chech valid digit
if (digit == -1 || digit >= radix) {
return val;
}
val *= (unsigned int) radix;
val += (unsigned int) digit;
}
return val;
}

84
src/cmd_common.h Normal file
View File

@ -0,0 +1,84 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
//
// Get the current open file path.
//
const char *GetCurrentFilePath(void);
//
// Get the currently open firmware image buffer.
//
unsigned char *GetFirmwareImage(unsigned int *pSize);
//
// Load a firmware image from a file path.
//
int LoadFirmwareImage(const char *path);
//
// Returns 1 if a firmware image is open, 0 otherwise.
//
int RequireFirmwareImage(void);
//
// Get the current command processor exiting status.
//
int IsExiting(void);
//
// Start the command processor exiting process.
//
void DoExit(void);
//
// Parse a number from an argument list.
//
uint32_t ParseArgNumber(const char *arg);
// ----- command procs
void CmdProcHelp(int argc, const char **argv);
void CmdProcInfo(int argc, const char **argv);
void CmdProcVerify(int argc, const char **argv);
void CmdProcMap(int argc, const char **argv);
void CmdProcLoad(int argc, const char **argv);
void CmdProcSave(int argc, const char **argv);
void CmdProcClean(int argc, const char **argv);
void CmdProcRestore(int argc, const char **argv);
void CmdProcExport(int argc, const char **argv);
void CmdProcImport(int argc, const char **argv);
void CmdProcLoc(int argc, const char **argv);
void CmdProcEB(int argc, const char **argv);
void CmdProcDB(int argc, const char **argv);
void CmdProcMD5(int argc, const char **argv);
void CmdProcUser(int argc, const char **argv);
void CmdProxFix(int argc, const char **argv);
void CmdProcCompact(int argc, const char **argv);
void CmdProcQuit(int argc, const char **argv);
// ----- command help procs
void CmdHelpHelp(void);
void CmdHelpInfo(void);
void CmdHelpVerify(void);
void CmdHelpMap(void);
void CmdHelpLoad(void);
void CmdHelpSave(void);
void CmdHelpClean(void);
void CmdHelpRestore(void);
void CmdHelpExport(void);
void CmdHelpImport(void);
void CmdHelpLoc(void);
void CmdHelpEB(void);
void CmdHelpDB(void);
void CmdHelpMD5(void);
void CmdHelpUser(void);
void CmdHelpFix(void);
void CmdHelpCompact(void);
void CmdHelpQuit(void);

121
src/cmd_compact.c Normal file
View File

@ -0,0 +1,121 @@
#include "cmd_common.h"
#include "firmware.h"
#include "blowfish.h"
#include <string.h>
void CmdHelpCompact(void) {
puts("");
puts("Usage: compact");
puts("");
puts("Recompresses each of the firmware's modules. Recompressing the modules may free");
puts("up space to be used for larger data.");
}
void CmdProcCompact(int argc, const char **argv) {
//compact the firmware. We do this by recompressing the binaries and relocating
//them to save as much space as possible. We will use the lower granularity
//wherever appropriate to move all unused space to the end.
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
if (arm9Static == NULL || arm7Static == NULL || arm9Secondary == NULL || arm7Secondary == NULL || rsrc == NULL) {
if (arm9Static == NULL) printf("The ARM9 static module could not be decompressed.\n");
if (arm7Static == NULL) printf("The ARM7 static module could not be decompressed.\n");
if (arm9Secondary == NULL) printf("The ARM9 secondary module could not be decompressed.\n");
if (arm7Secondary == NULL) printf("The ARM7 secondary module could not be decompressed.\n");
if (rsrc == NULL) printf("The resources pack could not be decompressed.\n");
goto End;
}
puts("");
//recompress each module
unsigned int arm9StaticRecompSize, arm7StaticRecompSize, arm9SecondaryRecompSize, arm7SecondaryRecompSize, rsrcRecompSize;
unsigned char *arm9StaticRecomp = CxCompressLZ(arm9Static, arm9StaticUncompressed, &arm9StaticRecompSize);
arm9StaticRecomp = CxPadCompressed(arm9StaticRecomp, arm9StaticRecompSize, 8, &arm9StaticRecompSize);
printf("ARM9 static : %08X -> %08X\n", arm9StaticSize, arm9StaticRecompSize);
unsigned char *arm7StaticRecomp = CxCompressLZ(arm7Static, arm7StaticUncompressed, &arm7StaticRecompSize);
arm7StaticRecomp = CxPadCompressed(arm7StaticRecomp, arm7StaticRecompSize, 8, &arm7StaticRecompSize);
printf("ARM7 static : %08X -> %08X\n", arm7StaticSize, arm7StaticRecompSize);
unsigned char *arm9SecondaryRecomp = CxCompressAshFirmware(arm9Secondary, arm9SecondaryUncompressed, &arm9SecondaryRecompSize);
arm9SecondaryRecomp = CxPadCompressed(arm9SecondaryRecomp, arm9SecondaryRecompSize, 8, &arm9SecondaryRecompSize);
printf("ARM9 secondary: %08X -> %08X\n", arm9SecondarySize, arm9SecondaryRecompSize);
unsigned char *arm7SecondaryRecomp = CxCompressAshFirmware(arm7Secondary, arm7SecondaryUncompressed, &arm7SecondaryRecompSize);
arm7SecondaryRecomp = CxPadCompressed(arm7SecondaryRecomp, arm7SecondaryRecompSize, 8, &arm7SecondaryRecompSize);
printf("ARM7 secondary: %08X -> %08X\n", arm7SecondarySize, arm7SecondaryRecompSize);
unsigned char *rsrcRecomp = CxCompressAshFirmware(rsrc, rsrcUncompressed, &rsrcRecompSize);
rsrcRecomp = CxPadCompressed(rsrcRecomp, rsrcRecompSize, 8, &rsrcRecompSize);
printf("Resources : %08X -> %08X\n", rsrcSize, rsrcRecompSize);
unsigned int size1 = arm9StaticSize + arm7StaticSize + arm9SecondarySize + arm7SecondarySize + rsrcSize;
unsigned int size2 = arm9StaticRecompSize + arm7StaticRecompSize + arm9SecondaryRecompSize + arm7SecondaryRecompSize + rsrcRecompSize;
puts("");
printf("Total saved: %08X\n", size1 - size2);
//encrypt modules
BfEncrypt(arm9StaticRecomp, arm9StaticRecompSize, buffer);
BfEncrypt(arm7StaticRecomp, arm7StaticRecompSize, buffer);
//place updated module
unsigned int offs = 0x200;
memcpy(buffer + offs, arm9StaticRecomp, arm9StaticRecompSize);
hdr->arm9RomAddrScale = 1; // 8x
hdr->arm9StaticRomAddr = (offs / 8);
offs += arm9StaticRecompSize;
memcpy(buffer + offs, arm7StaticRecomp, arm7StaticRecompSize);
hdr->arm7RomAddrScale = 1; // 8x
hdr->arm7StaticRomAddr = (offs / 8);
offs += arm7StaticRecompSize;
memcpy(buffer + offs, arm9SecondaryRecomp, arm9SecondaryRecompSize);
hdr->arm9SecondaryRomAddr = (offs / 8);
offs += arm9SecondaryRecompSize;
memcpy(buffer + offs, arm7SecondaryRecomp, arm7SecondaryRecompSize);
hdr->arm7SecondaryRomAddr = (offs / 8);
offs += arm7SecondaryRecompSize;
memcpy(buffer + offs, rsrcRecomp, rsrcRecompSize);
hdr->resourceRomAddr = (offs / 8);
free(arm9StaticRecomp);
free(arm7StaticRecomp);
free(arm9SecondaryRecomp);
free(arm7SecondaryRecomp);
free(rsrcRecomp);
End:
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

112
src/cmd_eb.c Normal file
View File

@ -0,0 +1,112 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpEB(void) {
puts("");
puts("Usage: eb <address> <bytes...>");
puts("");
puts("Bytes are separated by spaces. The byte values and address are interpreted in");
puts("hexadecimal by default. Prefix with '0n' to input decimal, or '0o' for octal.");
puts("Hexadecimal values may optionally be prefixed with '0x' or suffixed with 'h'.");
}
void CmdProcEB(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
if (argc < 2) {
CmdHelpEB();
return;
}
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
uint32_t addr = ParseArgNumber(argv[1]);
if (addr >= size) {
printf("Address %08X is out of bounds.\n", addr);
return;
}
int i;
for (i = 2; i < argc && addr < size; i++) {
uint8_t bval = ParseArgNumber(argv[i]);
buffer[addr++] = bval;
}
if (i < argc) {
puts("");
printf("Write truncated to %d byte(s).\n", i - 2);
}
}
void CmdHelpDB(void) {
puts("");
puts("Usage: db <address> [size]");
puts("");
puts("Dumps the bytes at the specified address. If size is not specified, then up to");
puts("128 bytes are dumped. The address is interpreted in hexadecimal by default.");
puts("Prefix with '0n' to input decimal, or '0o' for octal. Hexadecimal values may");
puts("optionally be prefixed with '0x' or suffixed with 'h'.");
}
void CmdProcDB(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
if (argc < 2) {
CmdHelpDB();
return;
}
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
uint32_t addr = ParseArgNumber(argv[1]);
if (addr >= size) {
printf("Address %08X is out of bounds.\n", addr);
return;
}
uint32_t nBytes = 0x80;
if (nBytes > (size - addr)) nBytes = size - addr;
if (argc >= 3) {
nBytes = ParseArgNumber(argv[2]);
}
if (nBytes > (size - addr)) {
nBytes = size - addr;
printf("Dump truncated to %d bytes.\n", nBytes);
}
puts("");
printf(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F | 0123456789ABCDEF \n");
printf("----------+-------------------------------------------------+------------------\n");
uint32_t rowAddr = (addr & ~0xF);
uint32_t rowLast = (addr + nBytes - 1) & ~0xF;
while (rowAddr <= rowLast) {
printf(" %08X | ", rowAddr);
for (unsigned int i = 0; i < 16; i++) {
uint32_t baddr = rowAddr + i;
if (baddr >= addr && baddr < (addr + nBytes)) printf("%02X ", buffer[baddr]);
else printf(" ");
}
printf("| ");
for (unsigned int i = 0; i < 16; i++) {
uint32_t baddr = rowAddr + i;
if (baddr >= addr && baddr < (addr + nBytes)) {
unsigned char b = buffer[baddr];
if (b < 0x20 || b >= 0x7F) b = '.';
printf("%c", b);
}
else printf(" ");
}
printf("\n");
rowAddr += 0x10;
}
}

386
src/cmd_export.c Normal file
View File

@ -0,0 +1,386 @@
#include "cmd_common.h"
#include "firmware.h"
#include "blowfish.h"
#include "compression.h"
#include <string.h>
void CmdHelpExport(void) {
puts("");
puts("Usage: export <module> <filename> [flags...]");
puts("");
puts("Use one of the following for the module parameter:");
puts(" arm9 ARM9 Static module");
puts(" arm7 ARM7 static module");
puts(" arm9s ARM9 Secondary module");
puts(" arm7s ARM7 Secondary module");
puts(" rsrc Resources pack");
puts("");
puts("Flags:");
puts(" -e Do not decrypt the module (ARM7 and ARM9 static)");
puts(" -c Do not decompress the module");
}
void CmdProcExport(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
if (argc < 3) {
CmdHelpExport();
return;
}
int decrypt = 1, decompress = 1;
const char *modname = argv[1];
const char *filename = argv[2];
for (int i = 3; i < argc; i++) {
if (strcmp(argv[i], "-e") == 0) {
decrypt = 0;
decompress = 0;
} else if (strcmp(argv[i], "-c") == 0) {
decompress = 0;
} else {
printf("Unrecognized flag %s.\n", argv[i]);
}
}
unsigned char *result = NULL;
unsigned int resultSize = 0;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//decompress module
CxCompressionType type9, type7, typeRsrc;
if (strcmp(modname, "arm9") == 0) {
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
if (decompress) {
result = arm9Static;
resultSize = arm9StaticUncompressed;
} else {
free(arm9Static);
resultSize = arm9StaticSize;
result = malloc(resultSize);
memcpy(result, buffer + arm9StaticRomAddr, resultSize);
if (decrypt) {
//decrypt
BfDecrypt(result, resultSize, buffer);
}
}
} else if (strcmp(modname, "arm7") == 0) {
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
if (decompress) {
result = arm7Static;
resultSize = arm7StaticUncompressed;
} else {
free(arm7Static);
resultSize = arm7StaticSize;
result = malloc(resultSize);
memcpy(result, buffer + arm7StaticRomAddr, resultSize);
if (decrypt) {
//decrypt
BfDecrypt(result, resultSize, buffer);
}
}
} else if (strcmp(modname, "arm9s") == 0) {
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
if (decompress) {
//write decompressed
result = arm9Secondary;
resultSize = arm9SecondaryUncompressed;
} else {
//copy compressed
free(arm9Secondary);
resultSize = arm9SecondarySize;
result = malloc(resultSize);
memcpy(result, buffer + arm9SecondaryRomAddr, resultSize);
}
} else if (strcmp(modname, "arm7s") == 0) {
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
if (decompress) {
//write decompressed
result = arm7Secondary;
resultSize = arm7SecondaryUncompressed;
} else {
//copy compressed
free(arm7Secondary);
resultSize = arm7SecondarySize;
result = malloc(resultSize);
memcpy(result, buffer + arm7SecondaryRomAddr, resultSize);
}
} else if (strcmp(modname, "rsrc") == 0) {
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
if (decompress) {
//write decompressed
result = rsrc;
resultSize = rsrcUncompressed;
} else {
//copy compressed
free(rsrc);
resultSize = rsrcSize;
result = malloc(resultSize);
memcpy(result, buffer + rsrcRomAddr, resultSize);
}
} else {
printf("Unknown module name '%s'.\n", modname);
return;
}
if (result == NULL) {
puts("Could not extract module.");
return;
}
FILE *fp = fopen(filename, "wb");
if (fp == NULL) {
printf("Could not open '%s' for write access.\n", filename);
free(result);
return;
}
fwrite(result, resultSize, 1, fp);
fclose(fp);
free(result);
}
void CmdHelpImport(void) {
puts("");
puts("Usage: import <module> <filename> [flags...]");
puts("");
puts("Import a module into this firmware image. The source file may be uncompressed,");
puts("compressed, or compressed and encrypted. Only the ARM9 and ARM7 static modules");
puts("are encrypted.");
puts("");
puts("Use one of the following for the module parameter:");
puts(" arm9 ARM9 Static module");
puts(" arm7 ARM7 static module");
puts(" arm9s ARM9 Secondary module");
puts(" arm7s ARM7 Secondary module");
puts(" rsrc Resources pack");
puts("");
puts("Flags:");
puts(" -c Imported module is compressed.");
puts(" -e Imported module is compressed and encrypted.");
}
void CmdProcImport(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
if (argc < 2) {
CmdHelpImport();
return;
}
int decrypt = 1, decompress = 1;
const char *modname = argv[1];
const char *filename = argv[2];
for (int i = 3; i < argc; i++) {
if (strcmp(argv[i], "-e") == 0) {
decrypt = 0;
decompress = 0;
} else if (strcmp(argv[i], "-c") == 0) {
decompress = 0;
} else {
printf("Unrecognized flag %s.\n", argv[i]);
}
}
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
printf("Could not open '%s' for read access.\n", filename);
return;
}
unsigned int inSize, padSize;
unsigned char *inbuf;
fseek(fp, 0, SEEK_END);
inSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
//calculate padded size
if (!decompress) {
//pad size: for compressed (regardless of encryption), pad to 8.
padSize = (inSize + 7) & ~7;
} else {
//else: no padding
padSize = inSize;
}
inbuf = calloc(padSize, 1);
fread(inbuf, inSize, 1, fp);
fclose(fp);
inSize = padSize;
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//locate the load addresses for secondary modules and resources pack
GetSecondaryResourceLoadAddresses(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed, &arm9SecondaryRamAddr, &arm7SecondaryRamAddr, &rsrcRamAddr);
//can discard uncompressed binaries
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
//pull out compressed+encrypted modules
arm9Static = malloc(arm9StaticSize);
arm7Static = malloc(arm7StaticSize);
arm9Secondary = malloc(arm9SecondarySize);
arm7Secondary = malloc(arm7SecondarySize);
rsrc = malloc(rsrcSize);
memcpy(arm9Static, buffer + arm9StaticRomAddr, arm9StaticSize);
memcpy(arm7Static, buffer + arm7StaticRomAddr, arm7StaticSize);
memcpy(arm9Secondary, buffer + arm9SecondaryRomAddr, arm9SecondarySize);
memcpy(arm7Secondary, buffer + arm7SecondaryRomAddr, arm7SecondarySize);
memcpy(rsrc, buffer + rsrcRomAddr, rsrcSize);
//get module name
const char *const modnames[] = { "arm9", "arm7", "arm9s", "arm7s", "rsrc" };
int modno = -1;
for (int i = 0; i < 5; i++) {
if (strcmp(modname, modnames[i]) == 0) {
modno = i;
break;
}
}
uint32_t modSizes[] = { arm9StaticSize, arm7StaticSize, arm9SecondarySize, arm7SecondarySize, rsrcSize };
unsigned char *mods[] = { arm9Static, arm7Static, arm9Secondary, arm7Secondary, rsrc };
CxCompressionType modComps[] = { CX_COMPRESSION_NONE, CX_COMPRESSION_NONE, type9, type7, typeRsrc };
//replace module
{
free(mods[modno]);
modSizes[modno] = 0;
if (decompress) {
//source file is uncompressed, unencrypted.
if (modno == 0 || modno == 1) {
//ARM9 or ARM7 static: must be LZ compressed, then encrypted
unsigned int compSize;
unsigned char *comp = CxCompressLZ(inbuf, inSize, &compSize);
comp = CxPadCompressed(comp, compSize, 8, &compSize);
free(inbuf);
//encrypt
BfEncrypt(comp, compSize, buffer);
mods[modno] = comp;
modSizes[modno] = compSize;
} else {
//secondary/resource: must be either LZ or ASH compressed
unsigned char *comp = NULL;
unsigned int compSize = 0;
if (modComps[modno] == CX_COMPRESSION_ASH) {
//ASH compress
printf("Compressing...\n");
comp = CxCompressAshFirmware(inbuf, inSize, &compSize);
printf("Done.\n");
} else {
//LZ compress
comp = CxCompressLZ(inbuf, inSize, &compSize);
}
comp = CxPadCompressed(comp, compSize, 8, &compSize);
free(inbuf);
mods[modno] = comp;
modSizes[modno] = compSize;
}
} else if (decrypt) {
//source file is compressed, unencrypted.
if (modno == 0 || modno == 1) {
//static modules: must be encrypted
BfEncrypt(inbuf, inSize, buffer);
} else {
//secondary/resource modules: not encrypted
}
mods[modno] = inbuf;
modSizes[modno] = inSize;
} else {
//source file is compressed, encrypted.
mods[modno] = inbuf;
modSizes[modno] = inSize;
}
}
//check size
uint32_t totalSize = 0;
for (int i = 0; i < 5; i++) {
totalSize += modSizes[i];
totalSize = (totalSize + 7) & ~7;
}
//get max address
uint32_t maxAddr = hdr->nvramUserConfigAddr * 8 - 0x400;
if (HasTwlSettings(hdr->ipl2Type)) maxAddr -= 0x600;
if (maxAddr > size) maxAddr = size;
if ((totalSize + 0x200) >= maxAddr) {
printf("The module is too large.\n");
goto End;
}
//write modules
uint32_t curOffs = 0x200;
for (int i = 0; i < 5; i++) {
//write offset
switch (i) {
case 0: hdr->arm9StaticRomAddr = curOffs / 8; hdr->arm9RomAddrScale = 1; break;
case 1: hdr->arm7StaticRomAddr = curOffs / 8; hdr->arm7RomAddrScale = 1; break;
case 2: hdr->arm9SecondaryRomAddr = curOffs / 8; break;
case 3: hdr->arm7SecondaryRomAddr = curOffs / 8; break;
case 4: hdr->resourceRomAddr = curOffs / 8; break;
}
//get source
unsigned char *src = mods[i];
unsigned int modSize = modSizes[i];
memcpy(buffer + curOffs, src, modSize);
curOffs += modSize;
curOffs = (curOffs + 7) & ~7;
}
UpdateFirmwareModuleChecksums(buffer, size);
End:
for (int i = 0; i < 5; i++) {
if (mods[i] != NULL) free(mods[i]);
}
}

169
src/cmd_fix.c Normal file
View File

@ -0,0 +1,169 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpFix(void) {
puts("");
puts("Usage: fix");
puts("");
puts("Fixes incorrect fields in the firmware. The CRCs of the static, secondary, and");
puts("resource modules are corrected. The CRCs of the wireless initialization tables,");
puts("user configuration, and wireless connection settings are corrected.");
}
static void UpgradeNcdVersion(FlashUserConfigData *ncd) {
if (ncd->version == 5) return; // correct
printf("Unspported user configuration version %d.\n", ncd->version);
}
void CmdProxFix(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
FlashHeader *hdr = (FlashHeader *) buffer;
FlashRfBbInfo *wl = (FlashRfBbInfo *) (buffer + 0x2A);
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//1. correct static module CRC
if (arm9Static != NULL && arm7Static != NULL) {
uint16_t staticCrc = hdr->staticCrc;
uint16_t staticCrc2 = ComputeStaticCrc(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed);
if (staticCrc != staticCrc2) {
hdr->staticCrc = staticCrc2;
printf("Corrected static module CRC (%04X -> %04X)\n", staticCrc, staticCrc2);
}
} else {
puts("Could not decompress static modules.");
}
//2. correct secondary module CRC
if (arm9Secondary != NULL && arm7Secondary != NULL) {
uint16_t secondaryCrc = hdr->secondaryCrc;
uint16_t secondaryCrc2 = ComputeSecondaryCrc(arm9Secondary, arm9SecondaryUncompressed, arm7Secondary, arm7SecondaryUncompressed);
if (secondaryCrc != secondaryCrc2) {
hdr->secondaryCrc = secondaryCrc2;
printf("Corrected secondary module CRC (%04X -> %04X)\n", secondaryCrc, secondaryCrc2);
}
} else {
puts("Could not decompress secondary modules.");
}
//3. correct resources CRC
if (rsrc != NULL) {
uint16_t rsrcCrc = hdr->resourceCrc;
uint16_t rsrcCrc2 = ComputeCrc(rsrc, rsrcUncompressed, 0xFFFF);
if (rsrcCrc != rsrcCrc2) {
hdr->resourceCrc = rsrcCrc2;
printf("Corrected resources pack CRC (%04X -> %04X)\n", rsrcCrc, rsrcCrc2);
}
} else {
puts("Could not decompress resources pack.");
}
//4. correct wireless table CRC
{
uint16_t wlCrc = wl->crc;
uint16_t wlCrc2 = ComputeCrc(buffer + 0x2A + 2, wl->tableSize, 0);
if (wl->tableSize < (0x200 - 0x2E) && wlCrc != wlCrc2) {
wl->crc = wlCrc2;
printf("Corrected wireless init CRC (%04X -> %04X)\n", wlCrc, wlCrc2);
}
}
int hasExConfig = HasExConfig(hdr->ipl2Type);
int hasTwlConfig = HasTwlSettings(hdr->ipl2Type);
unsigned int ncdAddr = hdr->nvramUserConfigAddr * 8;
//5. correct connection settings CRCs
if (ncdAddr >= 0x400) {
unsigned int connAddr = ncdAddr - 0x400;
for (int i = 0; i < 3; i++) {
FlashConnSetting *conn = (FlashConnSetting *) (buffer + connAddr + i * 0x100);
if (conn->setType == 0xFF) continue;
//check CRC
uint16_t crc = conn->crc;
uint16_t crc2 = ComputeCrc(conn, sizeof(FlashConnSetting)-2, 0);
if (crc != crc2) {
conn->crc = crc2;
printf("Corrected connection %d CRC (%04X -> %04X)\n", i, crc, crc2);
}
}
if (hasTwlConfig && connAddr >= 0x600) {
unsigned int connExAddr = connAddr - 0x600;
for (int i = 0; i < 3; i++) {
FlashConnExSetting *conn = (FlashConnExSetting *) (buffer + connExAddr + i * 0x200);
if (conn->base.setType == 0xFF) continue;
uint16_t crc = conn->base.crc;
uint16_t crc2 = ComputeCrc(&conn->base, sizeof(FlashConnSetting)-2, 0);
if (crc != crc2) {
conn->base.crc = crc2;
printf("Corrected connection %d CRC (%04X -> %04X)\n", i + 3, crc, crc2);
}
uint16_t exCrc = conn->exCrc;
uint16_t exCrc2 = ComputeCrc(&conn->base + 1, sizeof(FlashConnExSetting)-sizeof(FlashConnSetting)-2, 0);
if (exCrc != exCrc2) {
printf("Corrected connection %d CRC (%04X -> %04X)\n", i + 3, exCrc, exCrc2);
}
}
}
}
//6. correct user data CRCs
if (ncdAddr < size && (ncdAddr + 0x200) < size) {
for (int i = 0; i < 2; i++) {
FlashUserConfigData *ncd = (FlashUserConfigData *) (buffer + ncdAddr + i * 0x100);
if (ncd->version != 5) {
UpgradeNcdVersion(ncd);
if (ncd->version != 5) continue;
}
uint16_t crc = ncd->crc;
uint16_t crc2 = ComputeCrc(ncd, FLASH_NCD_SIZE-4, 0xFFFF);
if (crc != crc2) {
ncd->crc = crc2;
printf("Corrected user config %d CRC (%04X -> %04X)\n", i, crc, crc2);
}
if (hasExConfig) {
if (ncd->exVersion != 1) {
ncd->exVersion = 1;
}
uint16_t exCrc = ncd->exCrc;
uint16_t exCrc2 = ComputeCrc(&ncd->exVersion, FLASH_NCD_EX_SIZE-2, 0xFFFF);
if (exCrc != exCrc2) {
ncd->exCrc = exCrc2;
printf("Corrected user config %d CRC (%04X -> %04X)\n", i, exCrc, exCrc2);
}
}
}
}
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

83
src/cmd_help.c Normal file
View File

@ -0,0 +1,83 @@
#include "cmd_common.h"
#include "firmware.h"
#include <string.h>
typedef struct HelpEntry_ {
const char *cmd;
void (*helpProc) (void);
} HelpEntry;
static const HelpEntry sHelpEntries[] = {
{ "help", CmdHelpHelp },
{ "quit", CmdHelpQuit },
{ "load", CmdHelpLoad },
{ "save", CmdHelpSave },
{ "info", CmdHelpInfo },
{ "verify", CmdHelpVerify },
{ "map", CmdHelpMap },
{ "compact", CmdHelpCompact },
{ "md5", CmdHelpMD5 },
{ "clean", CmdHelpClean },
{ "restore", CmdHelpRestore },
{ "fix", CmdHelpFix },
{ "import", CmdHelpImport },
{ "export", CmdHelpExport },
{ "user", CmdHelpUser },
{ "loc", CmdHelpLoc },
{ "eb", CmdHelpEB },
{ "db", CmdHelpDB }
};
void CmdHelpHelp(void) {
puts("");
puts("Usage: help [command]");
puts("");
puts("Prints help for a given command. If no command is specified, a list of commands");
puts("is printed.");
}
void CmdProcHelp(int argc, const char **argv) {
(void) argc;
(void) argv;
if (argc >= 2) {
const char *cmd = argv[1];
for (unsigned int i = 0; i < sizeof(sHelpEntries) / sizeof(sHelpEntries[0]); i++) {
if (stricmp(cmd, sHelpEntries[i].cmd) == 0) {
if (sHelpEntries[i].helpProc != NULL) sHelpEntries[i].helpProc();
else puts("Unimplemented.");
return;
}
}
printf("Unrecognized command '%s'.\n", cmd);
return;
}
puts("");
puts("Type help <command> for information about a command.");
puts("");
puts("File commands:");
puts(" load Load a firmware image.");
puts(" save Saves a firmware image to disk.");
puts("");
puts("Reporting commands:");
puts(" info Print basic information about a firmware image.");
puts(" loc Locate a module occupying an address.");
puts(" map Prints a map of the firmware address space.");
puts(" md5 Calculates the MD5 sum of the firmware image.");
puts(" user Prints the user configuration information.");
puts(" verify Verify a firmware image.");
puts("");
puts("Manipulation commands:");
puts(" clean Cleans the user configuration and wireless configuration.");
puts(" compact Compacts the firmware image.");
puts(" db Dump bytes from the firmware image.");
puts(" eb Enter bytes into the firmware image.");
puts(" export Exports a firmware component.");
puts(" fix Fixes problems in the firmware image.");
puts(" import Import a firmware component.");
puts(" restore Restore firmware configuration from a file.");
}

111
src/cmd_info.c Normal file
View File

@ -0,0 +1,111 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpInfo(void) {
puts("");
puts("Usage: info");
puts("");
puts("Prints basic information about a firmware image.");
puts("");
puts("The ROM offsets and sizes for the firmware's modules are listed, as well as their");
puts("destination addresses and the size of the module once uncompressed. If the module");
puts("cannot be decompressed, its size is listed as 0. Verify the state of the modules");
puts("using the verify command.");
}
static const char *GetIpl2TypeString(int type) {
if (type == IPL2_TYPE_NORMAL) type = 0;
const char *typestr = "DS";
if (type & IPL2_TYPE_USG) {
if (type & IPL2_TYPE_CPU_NTR) {
typestr = "DS Lite with CPU-NTR";
} else {
typestr = "DS Lite";
}
} else if (type & IPL2_TYPE_TWL) {
typestr = "DSi";
type &= ~(IPL2_TYPE_EXT_LANGUAGE | IPL2_TYPE_CHINESE | IPL2_TYPE_KOREAN);
}
const char *region = "World";
if (type & IPL2_TYPE_EXT_LANGUAGE) {
if (type & IPL2_TYPE_CHINESE) {
region = "iQue";
} else if (type & IPL2_TYPE_KOREAN) {
region = "Korea";
}
}
static char buffer[64];
sprintf(buffer, "%s (%s)", typestr, region);
return buffer;
}
void CmdProcInfo(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
FlashRfBbInfo *wl = (FlashRfBbInfo *) (buffer + 0x2A);
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//locate the load addresses for secondary modules and resources pack
GetSecondaryResourceLoadAddresses(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed, &arm9SecondaryRamAddr, &arm7SecondaryRamAddr, &rsrcRamAddr);
//print firmware info
printf("\n");
printf("Firmware Info:\n");
printf(" Build date : 20%02X/%02X/%02X %02X:%02X\n", hdr->timestamp[4], hdr->timestamp[3], hdr->timestamp[2], hdr->timestamp[1], hdr->timestamp[0]);
printf(" IPL2 type : %s\n", GetIpl2TypeString(hdr->ipl2Type));
printf(" Extended settings : %s\n", (hdr->ipl2Type != 0xFF && (hdr->ipl2Type & 0x40)) ? "yes" : "no");
printf(" Flash capacity : %d KB\n", 128 << hdr->flashCapacity);
printf("\n");
//Module info: ARM9,ARM7 static modules, ARM9,ARM7 secondary modules, resource blob
printf("Module Info: Offset Size Address Uncompressed\n");
printf(" ARM9 Static Module : %08X %08X %08X %08X\n", arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed);
printf(" ARM7 Static Module : %08X %08X %08X %08X\n", arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed);
printf(" ARM9 Secondary Module : %08X %08X %08X %08X\n", arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed);
printf(" ARM7 Secondary Module : %08X %08X %08X %08X\n", arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed);
printf(" Resources Pack : %08X %08X %08X %08X\n", rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed);
printf("\n");
uint16_t channels = wl->allowedChannel;
//Wireless info: RFU type, allowed channels, register values
printf("Wireless Info:\n");
printf(" RF Type : %s\n", GetRfType(wl->rfType));
printf(" Module Vendor : %02X %02X\n", wl->module, wl->vendor);
printf(" Serial : %02X%02X%02X%02X%02X\n", wl->serial[0], wl->serial[1], wl->serial[2], wl->serial[3], wl->serial[4]);
printf(" MAC Address : %02X-%02X-%02X-%02X-%02X-%02X\n", wl->macAddr[0], wl->macAddr[1], wl->macAddr[2], wl->macAddr[3], wl->macAddr[4], wl->macAddr[5]);
printf(" Allowed Channels : "); for (int i = 0; i < 16; i++) if (channels & (1 << i)) printf("%d ", i); printf("\n");
printf("\n");
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

46
src/cmd_load.c Normal file
View File

@ -0,0 +1,46 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpLoad(void) {
puts("");
puts("Usage: load <file name>");
puts("");
puts("Loads a firmare image from the given file path.");
}
void CmdProcLoad(int argc, const char **argv) {
if (argc < 2) {
CmdHelpLoad();
return;
}
const char *filename = argv[1];
LoadFirmwareImage(filename);
}
void CmdHelpSave(void) {
puts("");
puts("Usage: save [file name]");
puts("");
puts("Saves the working firmware image. A file name may optionally be specified.");
}
void CmdProcSave(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
const char *outpath = GetCurrentFilePath();
if (argc >= 2) {
outpath = argv[1];
}
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
FILE *fp = fopen(outpath, "wb");
if (fp == NULL) {
printf("Could not open '%s' for write access.\n", outpath);
}
fwrite(buffer, size, 1, fp);
fclose(fp);
}

62
src/cmd_loc.c Normal file
View File

@ -0,0 +1,62 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpLoc(void) {
puts("");
puts("Usage: loc <address>");
puts("");
puts("Locates the module that will be loaded at the specified address in RAM, and at");
puts("what offset it appears.");
}
void CmdProcLoc(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
if (argc < 2) {
CmdHelpLoc();
return;
}
const char *straddr = argv[1];
uint32_t addr = ParseArgNumber(straddr);
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//locate the load addresses for secondary modules and resources pack
GetSecondaryResourceLoadAddresses(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed, &arm9SecondaryRamAddr, &arm7SecondaryRamAddr, &rsrcRamAddr);
if (arm9StaticRamAddr && addr >= arm9StaticRamAddr && addr < (arm9StaticRamAddr + arm9StaticUncompressed)) {
printf("%08X: ARM9 Static Module + 0x%X\n", addr, addr - arm9StaticRamAddr);
} else if (arm7StaticRamAddr && addr >= arm7StaticRamAddr && addr < (arm7StaticRamAddr + arm7StaticUncompressed)) {
printf("%08X: ARM7 Static Module + 0x%X\n", addr, addr - arm7StaticRamAddr);
} else if (arm9SecondaryRamAddr && addr >= arm9SecondaryRamAddr && addr < (arm9SecondaryRamAddr + arm9SecondaryUncompressed)) {
printf("%08X: ARM9 Secondary Module + 0x%X\n", addr, addr - arm9SecondaryRamAddr);
} else if (arm7SecondaryRamAddr && addr >= arm7SecondaryRamAddr && addr < (arm7SecondaryRamAddr + arm7SecondaryUncompressed)) {
printf("%08X: ARM7 Secondary Module + 0x%X\n", addr, addr - arm7SecondaryRamAddr);
} else if (rsrcRamAddr && addr >= rsrcRamAddr && addr < (rsrcRamAddr + rsrcUncompressed)) {
printf("%08X: Resources Pack + 0x%X\n", addr, addr - rsrcRamAddr);
} else {
printf("No matches for address %08X.\n", addr);
}
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

119
src/cmd_map.c Normal file
View File

@ -0,0 +1,119 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpMap(void) {
puts("");
puts("Usage: map");
puts("");
puts("Prints a map of the firmware image's address space.");
}
typedef struct Region_ {
uint32_t start;
uint32_t size;
const char *name;
} Region;
static int RegionComparator(const void *e1, const void *e2) {
const Region *r1 = (const Region *) e1;
const Region *r2 = (const Region *) e2;
if (r1->start < r2->start) return -1;
if (r1->start > r2->start) return 1;
return 0;
}
void CmdProcMap(int argc, const char **argv) {
//map out the firmware address regions.
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
if (arm9Static == NULL || arm7Static == NULL || arm9Secondary == NULL || arm7Secondary == NULL || rsrc == NULL) {
if (arm9Static == NULL) printf("The ARM9 static module could not be decompressed.\n");
if (arm7Static == NULL) printf("The ARM7 static module could not be decompressed.\n");
if (arm9Secondary == NULL) printf("The ARM9 secondary module could not be decompressed.\n");
if (arm7Secondary == NULL) printf("The ARM7 secondary module could not be decompressed.\n");
if (rsrc == NULL) printf("The resources pack could not be decompressed.\n");
goto End;
}
unsigned int ncdRomAddr = hdr->nvramUserConfigAddr * 4 * 2;
unsigned int ncdSize = 0x200;
unsigned int connSize = HasTwlSettings(hdr->ipl2Type) ? 0xA00 : 0x400;
unsigned int connRomAddr = ncdRomAddr - connSize;
Region regions[] = {
{ 0, 0x200, "Header" },
{ arm9StaticRomAddr, arm9StaticSize, "ARM9 Static" },
{ arm7StaticRomAddr, arm7StaticSize, "ARM7 Static" },
{ arm9SecondaryRomAddr, arm9SecondarySize, "ARM9 Secondary" },
{ arm7SecondaryRomAddr, arm7SecondarySize, "ARM7 Secondary" },
{ rsrcRomAddr, rsrcSize, "Resources Pack" },
{ connRomAddr, connSize, "Connection Settings" },
{ ncdRomAddr, ncdSize, "User Configuration" }
};
qsort(regions, sizeof(regions) / sizeof(Region), sizeof(Region), RegionComparator);
const char *fmtJct = " +----------------------------------------+-- %08X\n";
puts("");
unsigned int i = 0;
uint32_t curAddr = 0;
for (i = 0; i < sizeof(regions) / sizeof(regions[0]); i++) {
Region *rgn = &regions[i];
printf(fmtJct, curAddr);
char linebuf[64] = { 0 };
if (curAddr < rgn->start) {
//free space
int len = snprintf(linebuf, sizeof(linebuf), "Free Space (%d bytes)", rgn->start - curAddr);
printf(" |");
for (int i = 0; i < (40 - len) / 2; i++) putchar(' ');
printf(linebuf);
for (int i = 0; i < (40 - (40 - len) / 2 - len); i++) putchar(' ');
printf("|\n");
curAddr = rgn->start;
printf(fmtJct, curAddr);
}
//free space
int len = snprintf(linebuf, sizeof(linebuf), "%s (%d bytes)", rgn->name, rgn->size);
printf(" |");
for (int i = 0; i < (40 - len) / 2; i++) putchar(' ');
printf(linebuf);
for (int i = 0; i < (40 - (40 - len) / 2 - len); i++) putchar(' ');
printf("|\n");
curAddr = rgn->start + rgn->size;
}
printf(fmtJct, curAddr);
End:
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

204
src/cmd_ms5.c Normal file
View File

@ -0,0 +1,204 @@
#include "cmd_common.h"
#include "firmware.h"
#include <string.h>
#include <math.h>
void CmdHelpMD5(void) {
puts("");
puts("Usage: md5");
puts("");
puts("Prints out the MD5 digests of components of the firmware.");
}
//MD5 sine table
static const uint32_t k[] = {
0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
0x655b59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
};
//MD5 rotate table
static const int s[] = {
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
};
static uint32_t RotL(uint32_t v1, int amt){
return (v1 << amt) | (v1 >> (32 - amt));
}
static void ComputeMd5(const unsigned char *buf, unsigned int len, unsigned char *pDigest) {
unsigned int processedLen = len + 1; // added 1-bit
//compute padding size (to 56 bytes mod 64)
if ((processedLen % 64) < 56) {
processedLen += 56 - (processedLen % 64);
} else if ((processedLen % 64) > 56) {
processedLen += 64 + 56 - (processedLen % 64);
}
processedLen += 8;
unsigned char *processed = calloc(processedLen, 1);
memcpy(processed, buf, len);
processed[len] = 0x80;
uint64_t nBitsSrc = len * 8;
for (int i = 0; i < 8; i++) {
processed[processedLen - 8 + i] = (nBitsSrc >> (8 * i)) & 0xFF;
}
//initial MD5 state
unsigned int a0 = 0x67452301;
unsigned int b0 = 0xEFCDAB89;
unsigned int c0 = 0x98BADCFE;
unsigned int d0 = 0x10325476;
for (unsigned int n = 0; n < processedLen; n += 64) {
uint32_t chunk[16];
const unsigned char *chunksrc = processed + n;
for (int i = 0; i < 16; i++) {
chunk[i] = (chunksrc[i * 4 + 0] << 0) | (chunksrc[i * 4 + 1] << 8)
| (chunksrc[i * 4 + 2] << 16) | (chunksrc[i * 4 + 3] << 24);
}
uint32_t a = a0;
uint32_t b = b0;
uint32_t c = c0;
uint32_t d = d0;
for (int i = 0; i < 64; i++) {
uint32_t f = 0, g = 0;
switch ((i >> 4)) {
case 0:
f = (b & c) | ((~b) & d);
g = i;
break;
case 1:
f = (d & b) | ((~d) & c);
g = 5 * i + 1;
break;
case 2:
f = b ^ c ^ d;
g = 3 * i + 5;
break;
case 3:
f = c ^ (b | (~d));
g = 7 * i;
break;
}
uint32_t tmp = d;
d = c;
c = b;
b = b + RotL(a + f + k[i] + chunk[g % 16], s[i]);
a = tmp;
}
a0 += a;
b0 += b;
c0 += c;
d0 += d;
}
free(processed);
//write digest
for (int i = 0; i < 4; i++) *(pDigest++) = (a0 >> (8 * i)) & 0xFF;
for (int i = 0; i < 4; i++) *(pDigest++) = (b0 >> (8 * i)) & 0xFF;
for (int i = 0; i < 4; i++) *(pDigest++) = (c0 >> (8 * i)) & 0xFF;
for (int i = 0; i < 4; i++) *(pDigest++) = (d0 >> (8 * i)) & 0xFF;
}
static void PrintDigest(const unsigned char *digest) {
for (int i = 0; i < 16; i++) printf("%02X", digest[i]);
}
void CmdProcMD5(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//locate the load addresses for secondary modules and resources pack
GetSecondaryResourceLoadAddresses(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed, &arm9SecondaryRamAddr, &arm7SecondaryRamAddr, &rsrcRamAddr);
//digest buffers
unsigned char dFw[16], dStatic9c[16], dStatic9u[16], dStatic7c[16], dStatic7u[16];
unsigned char dSecondary9c[16], dSecondary9u[16], dSecondary7c[16], dSecondary7u[16];
unsigned char dRsrcu[16], dRsrcc[16];
ComputeMd5(buffer, size, dFw);
ComputeMd5(buffer + arm9StaticRomAddr, arm9StaticSize, dStatic9c);
ComputeMd5(buffer + arm7StaticRomAddr, arm7StaticSize, dStatic7c);
ComputeMd5(buffer + arm9SecondaryRomAddr, arm9SecondarySize, dSecondary9c);
ComputeMd5(buffer + arm7SecondaryRomAddr, arm7SecondarySize, dSecondary7c);
ComputeMd5(buffer + rsrcRomAddr, rsrcSize, dRsrcc);
ComputeMd5(arm9Static, arm9StaticUncompressed, dStatic9u);
ComputeMd5(arm7Static, arm7StaticUncompressed, dStatic7u);
ComputeMd5(arm9Secondary, arm9SecondaryUncompressed, dSecondary9u);
ComputeMd5(arm7Secondary, arm7SecondaryUncompressed, dSecondary7u);
ComputeMd5(rsrc, rsrcUncompressed, dRsrcu);
puts("");
printf("Raw Digest : "); PrintDigest(dFw); puts("");
puts("");
printf("Compressed Modules\n");
if (arm9Static != NULL) { printf(" ARM9 Static Digest : "); PrintDigest(dStatic9c); puts(""); }
if (arm7Static != NULL) { printf(" ARM7 Static Digest : "); PrintDigest(dStatic7c); puts(""); }
if (arm9Secondary != NULL) { printf(" ARM9 Secondary Digest : "); PrintDigest(dSecondary9c); puts(""); }
if (arm7Secondary != NULL) { printf(" ARM7 Secondary Digest : "); PrintDigest(dSecondary7c); puts(""); }
if (rsrc != NULL) { printf(" Resources Digest : "); PrintDigest(dRsrcc); puts(""); }
puts("");
printf("Uncompressed Modules\n");
if (arm9Static != NULL) { printf(" ARM9 Static Digest : "); PrintDigest(dStatic9u); puts(""); }
if (arm7Static != NULL) { printf(" ARM7 Static Digest : "); PrintDigest(dStatic7u); puts(""); }
if (arm9Secondary != NULL) { printf(" ARM9 Secondary Digest : "); PrintDigest(dSecondary9u); puts(""); }
if (arm7Secondary != NULL) { printf(" ARM7 Secondary Digest : "); PrintDigest(dSecondary7u); puts(""); }
if (rsrc != NULL) { printf(" Resources Digest : "); PrintDigest(dRsrcu); puts(""); }
if (arm9Static == NULL || arm7Static == NULL || arm9Secondary == NULL || arm7Secondary == NULL || rsrc == NULL) {
puts("");
printf("One or more modules failed to decompress.\n");
goto End;
}
End:
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

266
src/cmd_user.c Normal file
View File

@ -0,0 +1,266 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpUser(void) {
puts("");
puts("Usage: user");
puts("");
puts("Prints out the current user configuration settings. Only the current");
puts("information is printed.");
puts("The wireless connection settings are printed. When the advanced connection");
puts("settings are present, those are printed too.");
}
static int GetEffectiveConfig(FlashUserConfigData *ncd) {
int crc1OK = ComputeCrc(ncd, FLASH_NCD_SIZE-4, 0xFFFF) == ncd[0].crc;
int crc2OK = ComputeCrc(ncd, FLASH_NCD_SIZE-4, 0xFFFF) == ncd[1].crc;
if (!crc1OK && !crc2OK) return -1; // no good config data
if (crc1OK && !crc2OK) return 0; // config 1 good
if (crc2OK && !crc1OK) return 1; // config 2 good
if (((ncd[0].saveCount + 1) & 0x7F) == ncd[1].saveCount) return 1; // config 2 is newer
return 0; // config 1
}
static void PrintUcs2(const uint16_t *str, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
if (str[i] >= 0x20 && str[i] < 0x7F) putchar((char) str[i]);
else putchar('?'); // out of ASCII plane
}
}
static void PrintDate(const FlashDate *date) {
const char *const monthNames[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"
};
if (date->month == 0 || date->month > 12 || date->day == 0 || date->day > 31) {
printf("Invalid date (%02d/%02d)", date->month, date->day);
} else {
printf("%s %d", monthNames[date->month - 1], date->day);
}
}
static void PrintColor(int col) {
const char *const colorNames[] = {
"Gray", "Brown", "Red", "Pink",
"Orange", "Yellow", "Lime", "Green",
"Dark Green", "Sea Green", "Turquoise", "Blue",
"Dark Blue", "Purple", "Violet", "Magenta"
};
printf("%d (%s)", col, colorNames[col]);
}
static void PrintLanguage(FlashUserConfigData *ncd, int hasExConfig) {
const char *const languages[] = {
"Japanese", "English", "French", "German", "Italian", "Spanish",
"Chinese", "Korean"
};
if (!hasExConfig) {
int lang = ncd->language;
if (lang > 5) printf("Invalid (%d)", lang);
else printf("%s", languages[lang]);
} else {
int lang = ncd->exLanguage;
if (lang > 7) printf("Invalid (%d)", lang);
else printf("%s", languages[lang]);
}
}
static void PrintSSID(const unsigned char *ssid) {
//null-terminated SSIDs
for (unsigned int i = 0; i < 32; i++) {
if (ssid[i] == 0) break;
if (ssid[i] >= 0x20 && ssid[i] < 0x7F) putchar((char) ssid[i]);
else putchar('?');
}
}
static void PrintWEP(FlashConnSetting *set) {
if (set->wepMode == 0) {
//no WEP mode
printf("None");
return;
}
unsigned int keylen = 0;
switch (set->wepMode) {
case 1:
keylen = 40/8;
break;
case 2:
keylen = 104/8;
break;
case 3:
keylen = 128/8;
break;
}
printf("WEP %d (", keylen * 8);
for (unsigned int j = 0; j < keylen; j++) {
printf("%02X", set->wepKey[0][j]);
}
printf(")");
}
static void PrintWPA(FlashConnExSetting *set) {
if (set->wpaMode == 0 && set->base.wepMode == 0) {
//no WEP mode
printf("None");
return;
}
const char *const wpaTypes[] = {
"WPA-PSK (TKIP)",
"WPA2-PSK (TKIP)",
"WPA-PSK (AES)",
"WPA2-PSK (AES)"
};
printf("%s (", wpaTypes[set->wpaMode - 4]);
for (unsigned int i = 0; i < 64; i++) {
char c = set->passphrase[i];
if (!c) break;
putchar(c);
}
printf(")");
}
static void PrintIP(uint32_t addr) {
if (addr == 0) {
printf("Auto-obtain");
} else {
printf("%3d.%3d.%3d.%3d", (addr >> 0) & 0xFF, (addr >> 8) & 0xFF, (addr >> 16) & 0xFF, (addr >> 24) & 0xFF);
}
}
static void PrintNcd(FlashUserConfigData *ncd, int hasExConfig) {
printf("User configuration\n");
printf(" Nickname : "); PrintUcs2(ncd->nickname, ncd->nicknameLength); puts("");
printf(" Comment : "); PrintUcs2(ncd->comment, ncd->commentLength); puts("");
printf(" Birthday : "); PrintDate(&ncd->birthday); puts("");
printf(" Favorite Color : "); PrintColor(ncd->favoriteColor); puts("");
printf(" Language : "); PrintLanguage(ncd, hasExConfig); puts("");
}
static void PrintConnSetting(FlashConnSetting *set, int id) {
printf("Connection %d\n", id + 1);
if (set->setType == 0xFF) {
printf(" Not configured.\n");
puts("");
return;
}
printf(" SSID : "); PrintSSID(set->ssid); puts("");
printf(" Security : "); PrintWEP(set); puts("");
printf(" IP : "); PrintIP(set->ipAddr); puts("");
printf(" Gateway : "); PrintIP(set->gateway); puts("");
printf(" Subnet : "); PrintIP(((1 << set->subnetMask) - 1)); puts("");
printf(" DNS 1 : "); PrintIP(set->dns[0]); puts("");
printf(" DNS 2 : "); PrintIP(set->dns[1]); puts("");
uint64_t wfcId = (uint64_t) set->dwcUserIdLo;
wfcId |= ((uint64_t) set->dwcUserIdHi) << 32;
wfcId *= 1000ull;
uint64_t wfcId2 = (uint64_t) set->dwcUnattestedUserIdLo;
wfcId2 |= ((uint64_t) set->dwcUnattestedUserIdMid1) << 5;
wfcId2 |= ((uint64_t) set->dwcUnattestedUserIdMid2) << 21;
wfcId2 |= ((uint64_t) set->dwcUnattestedUserIdHi) << 37;
wfcId2 *= 1000ull;
printf(" WFC ID : %016llu (%016llu)\n", wfcId, wfcId2);
printf(" WFC Pass : %03X\n", set->pass);
puts("");
}
static void PrintConnExSetting(FlashConnExSetting *set, int id) {
printf("Connection %d\n", id + 1);
if (set->base.setType == 0xFF) {
printf(" Not configured.\n");
puts("");
return;
}
printf(" SSID : "); PrintSSID(set->base.ssid); puts("");
printf(" Security : "); if (set->wpaMode) PrintWPA(set); else PrintWEP(&set->base); puts("");
printf(" IP : "); PrintIP(set->base.ipAddr); puts("");
printf(" Gateway : "); PrintIP(set->base.gateway); puts("");
printf(" Subnet : "); PrintIP(((1 << set->base.subnetMask) - 1)); puts("");
printf(" DNS 1 : "); PrintIP(set->base.dns[0]); puts("");
printf(" DNS 2 : "); PrintIP(set->base.dns[1]); puts("");
printf(" MTU : %d\n", set->base.mtu);
uint64_t wfcId = (uint64_t) set->base.dwcUserIdLo;
wfcId |= ((uint64_t) set->base.dwcUserIdHi) << 32;
wfcId *= 1000ull;
uint64_t wfcId2 = (uint64_t) set->base.dwcUnattestedUserIdLo;
wfcId2 |= ((uint64_t) set->base.dwcUnattestedUserIdMid1) << 5;
wfcId2 |= ((uint64_t) set->base.dwcUnattestedUserIdMid2) << 21;
wfcId2 |= ((uint64_t) set->base.dwcUnattestedUserIdHi) << 37;
wfcId2 *= 1000ull;
printf(" WFC ID : %016llu (%016llu)\n", wfcId, wfcId2);
printf(" WFC Pass : %03X\n", set->base.pass);
puts("");
}
void CmdProcUser(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
FlashHeader *hdr = (FlashHeader *) buffer;
int hasExConfig = HasExConfig(hdr->ipl2Type);
int hasTwlConfig = HasTwlSettings(hdr->ipl2Type);
//address of user config
unsigned int ncdAddr = hdr->nvramUserConfigAddr * 8;
if (ncdAddr >= size || (ncdAddr + 0x200) > size) {
puts("Flash header user config address is invalid.");
return;
}
FlashUserConfigData *ncd = (FlashUserConfigData *) (buffer + ncdAddr);
//determine active configuration
int effective = GetEffectiveConfig(ncd);
if (effective == -1) {
puts("User configuation is invalid.");
return;
}
//print user config
puts("");
PrintNcd(&ncd[effective], hasExConfig);
//print access point settings
if (ncdAddr >= 0x400) {
unsigned int connAddr = ncdAddr - 0x400;
puts("");
for (int i = 0; i < 3; i++) {
PrintConnSetting((FlashConnSetting *) (buffer + connAddr + i * 0x100), i);
}
if (hasTwlConfig && connAddr >= 0x600) {
unsigned int connExAddr = connAddr - 0x600;
for (int i = 0; i < 3; i++) {
PrintConnExSetting((FlashConnExSetting *) (buffer + connExAddr + i * 0x200), i + 3);
}
}
}
}

106
src/cmd_verify.c Normal file
View File

@ -0,0 +1,106 @@
#include "cmd_common.h"
#include "firmware.h"
void CmdHelpVerify(void) {
puts("");
puts("Usage: verify");
puts("");
puts("Verifies the integrity of the firmware image. This command verifies the");
puts("checksums and data validity of the firmware.");
}
static int VerifyArm7Accessible(uint32_t addr, uint32_t size) {
//address must be in WRAM or main memory
if (addr < 0x02000000) return 0;
if (addr >= 0x04000000) return 0;
if ((addr + size) < addr) return 0;
if ((addr + size) >= 0x04000000) return 0;
return 1;
}
static int VerifyArm9StaticAddress(uint32_t addr, uint32_t size) {
//ARM9 static must be accessible from the ARM7.
if (!VerifyArm7Accessible(addr, size)) return 0;
return 1;
}
static int VerifyArm7StaticAddress(uint32_t addr, uint32_t size) {
//ARM7 static must be accessible from the ARM7.
if (!VerifyArm7Accessible(addr, size)) return 0;
return 1;
}
void CmdProcVerify(int argc, const char **argv) {
if (!RequireFirmwareImage()) return;
(void) argc;
(void) argv;
unsigned int size;
unsigned char *buffer = GetFirmwareImage(&size);
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
FlashRfBbInfo *wl = (FlashRfBbInfo *) (buffer + 0x2A);
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
int nErrors = 0;
printf("\nError list:\n");
//validate module data validity
if (arm9Static == NULL) { printf(" The ARM9 static module could not be decompressed.\n"); nErrors++; }
if (arm7Static == NULL) { printf(" The ARM7 static module could not be decompressed.\n"); nErrors++; }
if (arm9Secondary == NULL) { printf(" The ARM9 secondary module could not be decompressed.\n"); nErrors++; }
if (arm7Secondary == NULL) { printf(" The ARM7 secondary module could not be decompressed.\n"); nErrors++; }
if (rsrc == NULL) { printf(" The resources pack could not be decompressed.\n"); nErrors++; }
//validate load addresses
int arm9StaticLoadOK = VerifyArm9StaticAddress(arm9StaticRamAddr, arm9StaticUncompressed);
int arm7StaticLoadOK = VerifyArm7StaticAddress(arm7StaticRamAddr, arm7StaticUncompressed);
if (arm9Static != NULL && !arm9StaticLoadOK) { printf(" Invalid load address for ARM9 static module.\n"); nErrors++; }
if (arm7Static != NULL && !arm7StaticLoadOK) { printf(" Invalid load address for ARM7 static module.\n"); nErrors++; }
//get checksums from header
uint16_t staticCrc = hdr->staticCrc, secondaryCrc = hdr->secondaryCrc, rsrcCrc = hdr->resourceCrc;
uint16_t staticCrc2 = ComputeStaticCrc(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed);
uint16_t secondaryCrc2 = ComputeSecondaryCrc(arm9Secondary, arm9SecondaryUncompressed, arm7Secondary, arm7SecondaryUncompressed);
uint16_t rsrcCrc2 = ComputeCrc(rsrc, rsrcUncompressed, 0xFFFF);
if (arm9Static != NULL && arm7Static != NULL && staticCrc != staticCrc2) { printf(" Checksum mismatch for static module: %04X (expected %04X)\n", staticCrc2, staticCrc); nErrors++; }
if (arm9Secondary != NULL && arm7Secondary != NULL && secondaryCrc != secondaryCrc2) { printf(" Checksum mismatch for secondary module: %04X (expected %04X)\n", secondaryCrc2, secondaryCrc); nErrors++; }
if (rsrc != NULL && rsrcCrc != rsrcCrc2) { printf(" Checksum mismatch for resources pack: %04X (expected %04X)\n", rsrcCrc2, rsrcCrc); nErrors++; }
//validate wireless info
int isValidChannels = ((wl->allowedChannel & 0x8001) == 0) && ((wl->allowedChannel & 0x7FFE) != 0);
uint16_t wlCrc = 0;
if ((wl->tableSize + 0x2C) <= 0x200 || wl->tableSize < sizeof(*wl)) {
wlCrc = ComputeCrc(&wl->tableSize, wl->tableSize, 0);
} else { printf(" Invalid wireless init table size.\n"); nErrors++; }
if (wlCrc!= wl->crc) { printf(" CRC mismatch for wireless initialization.\n"); nErrors++; };
if (!IsValidRfType(wl->rfType)) { printf(" No valid wireless RF type specified.\n"); nErrors++; }
if (!isValidChannels) { printf(" Invalid wireless channel specification.\n"); nErrors++; }
//error footer
printf("\n%d error(s) found.\n\n", nErrors);
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}

1480
src/compression.c Normal file

File diff suppressed because it is too large Load Diff

39
src/compression.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#define CX_STREAM_EOF -1 // EOF return value for CxStreamReadCallback
typedef enum CxCompressionType_ {
CX_COMPRESSION_NONE,
CX_COMPRESSION_LZ,
CX_COMPRESSION_ASH
} CxCompressionType;
typedef int (*CxStreamReadCallback) (void *pArg);
unsigned char *CxDecompressLZ(const unsigned char *buffer, unsigned int size, unsigned int *uncompressedSize);
unsigned char *CxDecompressLZStream(unsigned int *uncompressedSize, CxStreamReadCallback callback, void *arg);
unsigned char *CxDecompressAsh(const unsigned char *buffer, unsigned int size, unsigned int *uncompressedSize);
unsigned char *CxCompressLZ(const unsigned char *buffer, unsigned int size, unsigned int *compressedSize);
unsigned char *CxCompressAsh(const unsigned char *buffer, unsigned int size, int nSymBits, int nDstBits, unsigned int nPasses, unsigned int *compressedSize);
static inline unsigned char *CxCompressAshFirmware(const unsigned char *buffer, unsigned int size, unsigned int *compressedSize) {
unsigned char *out = CxCompressAsh(buffer, size, 9, 11, 2, compressedSize);
if (out != NULL) {
uint32_t hdr = (*compressedSize << 2) | 0x80000000;
out[0] = (hdr >> 0) & 0xFF;
out[1] = (hdr >> 8) & 0xFF;
out[2] = (hdr >> 16) & 0xFF;
out[3] = (hdr >> 24) & 0xFF;
out[4] |= 0x80;
}
return out;
}
unsigned char *CxPadCompressed(unsigned char *comp, unsigned int size, unsigned int boundary, unsigned int *pOutSize);

426
src/firmware.c Normal file
View File

@ -0,0 +1,426 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "firmware.h"
#include "compression.h"
#include "blowfish.h"
uint16_t ComputeCrc(const void *p, unsigned int length, uint16_t init) {
const uint16_t tbl[] = {
0x0000, 0xCC01, 0xD801, 0x1400,
0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401,
0x5000, 0x9C01, 0x8801, 0x4400
};
uint16_t r = init;
const unsigned char *pp = (const unsigned char *) p;
for (unsigned int i = 0; i < length; i++) {
uint16_t c = (tbl[*pp & 0x0F] ^ (r >> 4)) ^ tbl[r & 0x0F];
r = (tbl[*pp >> 4] ^ (c >> 4)) ^ tbl[c & 0xF];
pp++;
}
return r;
}
uint16_t ComputeStaticCrc(const void *arm9Static, unsigned int arm9StaticSize, const void *arm7Static, unsigned int arm7StaticSize) {
uint16_t crc = ComputeCrc(arm9Static, arm9StaticSize, 0xFFFF);
return ComputeCrc(arm7Static, arm7StaticSize, crc);
}
uint16_t ComputeSecondaryCrc(const void *arm9Secondary, unsigned int arm9SecondarySize, const void *arm7Secondary, unsigned int arm7SecondarySize) {
uint16_t crc = ComputeCrc(arm9Secondary, arm9SecondarySize, 0xFFFF);
return ComputeCrc(arm7Secondary, arm7SecondarySize, crc);
}
void UpdateFirmwareModuleChecksums(unsigned char *buffer, unsigned int size) {
//header
FlashHeader *hdr = (FlashHeader *) buffer;
uint32_t arm9SecondaryRomAddr, arm9SecondarySize, arm9SecondaryRamAddr, arm9SecondaryUncompressed;
uint32_t arm7SecondaryRomAddr, arm7SecondarySize, arm7SecondaryRamAddr, arm7SecondaryUncompressed;
uint32_t arm9StaticRomAddr, arm9StaticSize, arm9StaticRamAddr, arm9StaticUncompressed;
uint32_t arm7StaticRomAddr, arm7StaticSize, arm7StaticRamAddr, arm7StaticUncompressed;
uint32_t rsrcRomAddr, rsrcSize, rsrcRamAddr, rsrcUncompressed;
//unpack firmware and data headers
CxCompressionType type9, type7, typeRsrc;
unsigned char *arm9Static = GetArm9StaticInfo(buffer, size, &arm9StaticRomAddr, &arm9StaticRamAddr, &arm9StaticSize, &arm9StaticUncompressed);
unsigned char *arm7Static = GetArm7StaticInfo(buffer, size, &arm7StaticRomAddr, &arm7StaticRamAddr, &arm7StaticSize, &arm7StaticUncompressed);
unsigned char *arm9Secondary = GetArm9SecondaryInfo(buffer, size, &arm9SecondaryRomAddr, &arm9SecondaryRamAddr, &arm9SecondarySize, &arm9SecondaryUncompressed, &type9);
unsigned char *arm7Secondary = GetArm7SecondaryInfo(buffer, size, &arm7SecondaryRomAddr, &arm7SecondaryRamAddr, &arm7SecondarySize, &arm7SecondaryUncompressed, &type7);
unsigned char *rsrc = GetResourcesPackInfo(buffer, size, &rsrcRomAddr, &rsrcRamAddr, &rsrcSize, &rsrcUncompressed, &typeRsrc);
//static module checksum
if (arm9Static != NULL && arm7Static != NULL) {
uint16_t sum = ComputeStaticCrc(arm9Static, arm9StaticUncompressed, arm7Static, arm7StaticUncompressed);
hdr->staticCrc = sum;
}
//secondary module checksum
if (arm9Secondary != NULL && arm7Secondary != NULL) {
uint16_t sum = ComputeSecondaryCrc(arm9Secondary, arm9SecondaryUncompressed, arm7Secondary, arm7SecondaryUncompressed);
hdr->secondaryCrc = sum;
}
//rsources checksum
if (rsrc != NULL) {
uint16_t sum = ComputeCrc(rsrc, rsrcUncompressed, 0xFFFF);
hdr->resourceCrc = sum;
}
if (arm9Static != NULL) free(arm9Static);
if (arm7Static != NULL) free(arm7Static);
if (arm9Secondary != NULL) free(arm9Secondary);
if (arm7Secondary != NULL) free(arm7Secondary);
if (rsrc != NULL) free(rsrc);
}
// ----- RF utilities
const char *GetRfType(int type) {
switch (type) {
case 1:
return "MAX2822";
case 2:
return "RF2958";
case 3:
return "MM3156";
case 4:
return "TEST";
case 5:
return "MTMBBP ES1";
case 6:
return "MM3218";
}
return "(unknown)";
}
int IsValidRfType(int type) {
if (type == 1 || type == 2 || type == 3 || type == 5 || type == 6) return 1;
return 0;
}
// ----- unpack routines
/*
* Searches for a byte pattern in the firmware image.
*/
static unsigned char *SearchPattern(const unsigned char *buf, unsigned int size, const unsigned char *search, unsigned int searchlen) {
if (searchlen > size) return NULL;
for (unsigned int i = 0; i < (size - searchlen); i++) {
if (memcmp(buf + i, search, searchlen) == 0) return (unsigned char *) (buf + i);
}
return NULL;
}
/*
* Searches for the decode_ash routine in the firmware image.
*/
static unsigned char *SearchDecodeAsh(const unsigned char *buf, unsigned int size) {
//signature of decode_ash in newer firmware versions
const unsigned char signature[] = {
0xF0, 0x5F, 0x2D, 0xE9, // PUSH { R4-R12, LR }
0x04, 0xD0, 0x4D, 0xE2, // SUB SP, #4
0x04, 0x40, 0x91, 0xE5, // LDR R4, [R1, #4]
0x64, 0x58, 0x24, 0xE0, // EOR R5, R4, R4, ROR #16
0xFF, 0x58, 0xC5, 0xE3, // BIC R5, R5, #0x00FF000000
0x64, 0x44, 0xA0, 0xE1, // MOV R4, R4, ROR #8
0x25, 0x44, 0x24, 0xE0, // EOR R4, R4, R5, LSR #8
0xFF, 0x44, 0xC4, 0xE3, // BIC R4, R4, #0xFF000000
};
unsigned char *p = SearchPattern(buf, size, signature, sizeof(signature));
if (p != NULL) return p;
//original decode_ash in older firmware versions
const unsigned char signature2[] = {
0xF0, 0x4F, 0x2D, 0xE9, // PUSH { R4-R11, LR }
0x0C, 0xD0, 0x4D, 0xE2, // SUB SP, #0xC
0x01, 0x90, 0xA0, 0xE1, // MOV sb, R1
0x05, 0x10, 0xD9, 0xE5, // LDRB R1, [sb, #5]
0x06, 0x20, 0xD9, 0xE5, // LDRB R2, [sb, #6]
0x08, 0x30, 0xD9, 0xE5, // LDRB R3, [sb, #8]
0x01, 0x48, 0xA0, 0xE1, // MOV R4, R1, LSL #16
0x02, 0x54, 0x84, 0xE1, // ORR R5, R4, R2, LSL #8
};
p = SearchPattern(buf, size, signature2, sizeof(signature2));
if (p != NULL) return p;
return NULL;
}
// ----- decompression routines
typedef struct StreamState_ {
const unsigned char *buf;
unsigned int pos;
unsigned int size;
} StreamState;
static int ReadBlowfishCallback(void *arg) {
BfStream *stream = (BfStream *) arg;
unsigned char b = BfDecryptStreamNext(stream);
if (stream->error) return CX_STREAM_EOF;
return b;
}
static int ReadNormalCallback(void *arg) {
StreamState *stream = (StreamState *) arg;
if (stream->pos >= stream->size) return CX_STREAM_EOF;
return stream->buf[stream->pos++];
}
unsigned char *UncompressLZBlowfish(const unsigned char *buffer, unsigned int size, unsigned int romAddr, uint32_t *pSize, uint32_t *pUncompressed) {
if (buffer == NULL || romAddr >= size) {
return NULL;
}
unsigned int uncompSize;
BfStream *stream = BfDecryptStreamInit(buffer + romAddr, size - romAddr, buffer);
unsigned char *uncomp = CxDecompressLZStream(&uncompSize, ReadBlowfishCallback, stream);
if (uncomp != NULL) {
*pUncompressed = uncompSize;
*pSize = (stream->srcpos + 7) & ~7; // source size (round up to multiple of blowfish block size)
}
BfDecryptStreamEnd(stream);
return uncomp;
}
unsigned char *UncompressLZNormal(const unsigned char *buffer, unsigned int size, unsigned int romAddr, uint32_t *pSize, uint32_t *pUncompressed) {
if (buffer == NULL || romAddr >= size) {
return NULL;
}
unsigned int uncompSize;
StreamState stream;
stream.buf = buffer;
stream.pos = romAddr;
stream.size = size;
unsigned char *uncomp = CxDecompressLZStream(&uncompSize, ReadNormalCallback, &stream);
if (uncomp != NULL) {
*pUncompressed = uncompSize;
*pSize = (stream.pos - romAddr + 7) & ~7; // source size (round up to multiple of blowfish block size)
}
return uncomp;
}
unsigned char *GetArm9StaticInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed) {
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
*pRomAddr = (4 * hdr->arm9StaticRomAddr) << hdr->arm9RomAddrScale;
*pRamAddr = 0x02800000 - ((hdr->arm9StaticRamAddr * 4) << hdr->arm9RamAddrScale);
*pSize = 0;
*pUncompressed = 0;
return UncompressLZBlowfish(buffer, size, *pRomAddr, pSize, pUncompressed);
}
unsigned char *GetArm7StaticInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed) {
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
*pRomAddr = (4 * hdr->arm7StaticRomAddr) << hdr->arm7RomAddrScale;
*pRamAddr = (hdr->arm7RamLocation ? 0x02800000 : 0x03810000) - ((hdr->arm7StaticRamAddr * 4) << hdr->arm7RamAddrScale);
*pSize = 0;
*pUncompressed = 0;
return UncompressLZBlowfish(buffer, size, *pRomAddr, pSize, pUncompressed);
}
static unsigned char *UncompressLZOrASH(const unsigned char *buffer, unsigned int size, unsigned int romAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType) {
//bounds check
if (romAddr > size) return NULL;
if ((size - romAddr) < 4) return NULL;
const unsigned char *p = buffer + romAddr;
if (*p == 0x10) {
//try decoding LZ
unsigned char *decp = UncompressLZNormal(buffer, size, romAddr, pSize, pUncompressed);
if (decp != NULL) {
*pType = CX_COMPRESSION_LZ;
return decp;
}
}
if ((size - romAddr) < 0xC) return NULL;
uint32_t header = *(const uint32_t *) (buffer + romAddr);
unsigned int compSize = (header & 0x00FFFFFF) >> 2;
if ((romAddr + compSize) > size) return NULL;
if ((romAddr + compSize) < romAddr) return NULL;
unsigned int uncompSize;
unsigned char *decp = CxDecompressAsh(buffer + romAddr, compSize, &uncompSize);
*pUncompressed = uncompSize;
*pSize = compSize;
*pType = CX_COMPRESSION_ASH;
return decp;
}
unsigned char *GetArm9SecondaryInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType) {
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
*pRomAddr = (4 * hdr->arm9SecondaryRomAddr) * 2;
*pRamAddr = 0;
*pSize = 0;
*pUncompressed = 0;
unsigned char *uncomp = NULL;
uncomp = UncompressLZOrASH(buffer, size, *pRomAddr, pSize, pUncompressed, pType);
return uncomp;
}
unsigned char *GetArm7SecondaryInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType) {
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
*pRomAddr = (4 * hdr->arm7SecondaryRomAddr) * 2;
*pRamAddr = 0;
*pSize = 0;
*pUncompressed = 0;
unsigned char *uncomp = NULL;
uncomp = UncompressLZOrASH(buffer, size, *pRomAddr, pSize, pUncompressed, pType);
return uncomp;
}
unsigned char *GetResourcesPackInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType) {
//flash header
FlashHeader *hdr = (FlashHeader *) buffer;
*pRomAddr = (4 * hdr->resourceRomAddr) * 2;
*pRamAddr = 0;
*pSize = 0;
*pUncompressed = 0;
unsigned char *uncomp = NULL;
uncomp = UncompressLZOrASH(buffer, size, *pRomAddr, pSize, pUncompressed, pType);
return uncomp;
}
void GetSecondaryResourceLoadAddresses(
const unsigned char *arm9Static,
unsigned int arm9StaticUncompressed,
const unsigned char *arm7Static,
unsigned int arm7StaticUncompressed,
uint32_t *pArm9SecondaryLoadAddr,
uint32_t *pArm7SecondaryLoadAddr,
uint32_t *pRsrcLoadAddr
) {
//locate the load addresses of the ARM9 secondary module and resources pack by locating the
//decode_ash function in the ARM9 static module. We look for thumb calls to this function
//and use that those to identify the load addresses.
if (arm9Static != NULL) {
unsigned char *pDecodeAsh = SearchDecodeAsh(arm9Static, arm9StaticUncompressed);
if (pDecodeAsh != NULL) {
//get offset to decode_ash
uint32_t ofsDecodeAsh = pDecodeAsh - arm9Static;
uint32_t rsrcRamAddr = 0x00000000;
uint32_t arm9SecondaryRamAddr = 0x00000000;
//search for thumb BL decode_ash
for (unsigned int i = 4; i < ((arm9StaticUncompressed & ~1) - 2); i += 2) {
uint32_t rel = ((((ofsDecodeAsh - (i + 4)) + 2) & ~3) >> 1) & 0x3FFFFF;
uint16_t u1 = *(uint16_t *) (arm9Static + i + 0);
uint16_t u2 = *(uint16_t *) (arm9Static + i + 2);
if ((u1 & 0xF800) != 0xF000) continue;
if ((u2 & 0xF800) != 0xE800) continue;
if ((u1 & 0x7FF) != ((rel >> 11) & 0x7FF)) continue;
if ((u2 & 0x7FF) != ((rel >> 0) & 0x7FF)) continue;
// case 1: (resources pack)
// LDR R0, =rsrcTarget
// LDR R1, =0x02200000
// BLX decode_ash
// case 2: (ARM9 Secondary)
// LDR R0, =Arm9SecondaryBase
// LDR R1, =0x022C0000
// BLX decode_ash
// case 3: (ARM7 Secondary)
// LDR R0, [R1, #0x0C]
// LDR R1, [R1, #0x10]
// BLX decode_ash
uint16_t instr1 = *(uint16_t *) (arm9Static + i - 4);
uint16_t instr2 = *(uint16_t *) (arm9Static + i - 2);
(void) instr2;
if ((instr1 & 0xFF00) == 0x4800) { // LDR R0, [PC, #X]
unsigned int pool = (i + ((instr1 & 0x00FF) << 2)) & ~3;
uint32_t addr = *(uint32_t *) (arm9Static + pool);
//printf("Case 1 at %08X (load to %08X)\n", i, *(uint32_t *) (arm9Static + pool));
if (arm9SecondaryRamAddr == 0) arm9SecondaryRamAddr = addr;
else rsrcRamAddr = addr;
} else if ((instr1 & 0xFFC7) == 0x68C0) { // LDR R0, [R1, #0xC]
}
}
*pArm9SecondaryLoadAddr = arm9SecondaryRamAddr;
*pRsrcLoadAddr = rsrcRamAddr;
} else {
//puts("Could not locate decode_ash.");
}
}
//the ARM7 secondary load address is determined by the ARM7.
if (arm7Static != NULL) {
//the ARM7 secondary laod addess is located at 027FF86C.
for (unsigned int i = 0; i < ((arm7StaticUncompressed & ~1) - 4); i += 2) {
uint16_t instr1 = *(uint16_t *) (arm7Static + i + 0);
uint16_t instr2 = *(uint16_t *) (arm7Static + i + 2);
uint16_t instr3 = *(uint16_t *) (arm7Static + i + 4);
(void) instr3;
if ((instr1 & 0xF800) != 0x4800) continue; // LDR R2, =Arm7SecondaryLoadAddr
if ((instr2 & 0xF800) != 0x4800) continue; // LDR R1, =0x027FF86C
unsigned int pool = ((i + 2) & ~3) + 4 + ((instr2 & 0xFF) << 2);
uint32_t val = *(uint32_t *) (arm7Static + pool);
if (val != 0x027FF86C) continue;
unsigned int pool2 = ((i + 0) & ~3) + 4 + ((instr1 & 0xFF) << 2);
uint32_t val2 = *(uint32_t *) (arm7Static + pool2);
*pArm7SecondaryLoadAddr = val2;
}
}
}
// ----- IPL2 type functions
int HasTwlSettings(int ipl2Type) {
if (ipl2Type == IPL2_TYPE_NORMAL) return 0; // original DS
if (ipl2Type & IPL2_TYPE_TWL) return 1;
return 0;
}
int HasExConfig(int ipl2Type) {
if (ipl2Type == IPL2_TYPE_NORMAL) return 0; // original DS
if (ipl2Type & (IPL2_TYPE_EXTENDED | IPL2_TYPE_TWL)) return 1;
return 0;
}

219
src/firmware.h Normal file
View File

@ -0,0 +1,219 @@
#pragma once
#include <stdint.h>
#include "compression.h"
// ----- FLASH structures
typedef struct FlashHeader_ {
uint16_t arm9SecondaryRomAddr; // +0x000 ARM9 Secondary Module ROM Address
uint16_t arm7SecondaryRomAddr; // +0x002 ARM7 Secondary Module ROM Address
uint16_t secondaryCrc; // +0x004 Secondary Module (ARM9+ARM7) CRC
uint16_t staticCrc; // +0x006 Static Module (ARM9+ARM7) CRC
uint32_t blowfishKey; // +0x008 Static Module blowfish key
uint16_t arm9StaticRomAddr; // +0x00C ARM9 Static Module ROM Address
uint16_t arm9StaticRamAddr; // +0x00E ARM9 Static Module RAM Address
uint16_t arm7StaticRomAddr; // +0x010 ARM7 Static Module ROM Address
uint16_t arm7StaticRamAddr; // +0x012 ARM7 Static Module RAM Address
uint16_t arm9RomAddrScale : 3; // +0x014 ARM9 Static Module ROM Address Scale
uint16_t arm9RamAddrScale : 3; // +0x014 ARM9 Static Module RAM Address Scale
uint16_t arm7RomAddrScale : 3; // +0x014 ARM7 Static Module ROM Address Scale
uint16_t arm7RamAddrScale : 3; // +0x014 ARM7 Static Module RAM Address Scale
uint16_t arm7RamLocation : 1; // +0x014 ARM7 Static Module RAM Address Selection (0=WRAM, 1=Main RAM)
uint16_t flashCapacity : 3; // +0x014 Flash memory capacity (dubious)
uint16_t resourceRomAddr; // +0x016 Resource Pack ROM Address
union {
struct {
unsigned char timestamp[5]; // +0x018 Firmware build time
unsigned char ipl2Type; // +0x01D IPL2 type
uint16_t pad1E; // +0x1E
};
uint32_t unscrambleKey[2]; // +0x018 Unscramble key
};
uint16_t nvramUserConfigAddr; // +0x020 NVRAM User Config Address
uint16_t field22;
uint16_t field24;
uint16_t resourceCrc; // +0x026 Resource Pack CRC
uint16_t field28;
} FlashHeader;
//some of these bits are conjecture
#define IPL2_TYPE_NORMAL 0xFF // Indicates Original DS
#define IPL2_TYPE_CPU_NTR 0x80 // Indicates use of CPU-NTR on USG firmware and display?
#define IPL2_TYPE_EXTENDED 0x40 // Indicates presence of extended settings
#define IPL2_TYPE_USG 0x20 // Indicates DS Lite type
#define IPL2_TYPE_TWL 0x10 // Indicates DSi type
#define IPL2_TYPE_KOREAN 0x04 // Indicates Korean language support
#define IPL2_TYPE_CHINESE 0x02 // Indicates Chinese language support
#define IPL2_TYPE_EXT_LANGUAGE 0x01 // Indicates extended language support
typedef struct FlashRfBbInfo_ {
uint16_t crc; // +0x02A CRC of table
uint16_t tableSize; // +0x02C Size of table
uint8_t vendor; // +0x02E Vendor ID
uint8_t module; // +0x02F Module ID
uint8_t serial[6]; // +0x030 Serial Number
uint8_t macAddr[6]; // +0x036 MAC Address
uint16_t allowedChannel; // +0x03C Allowed channels
uint16_t macFlags; // +0x03E MAC operation flags
uint8_t rfType; // +0x040 RF type
uint8_t rfRegisterBits; // +0x041 Width of RF register
uint8_t rfInitRegisterCount; // +0x042 Number of RF registers to initialize
uint8_t rfChannelRegisterCount; // +0x043 Number of RF registers per channel config
uint16_t macInitRegs[16]; // +0x044 MAC init regs
uint8_t bbInitRegs[0x69]; // +0x064 BBP init regs
uint8_t pad_;
} FlashRfBbInfo;
typedef struct FlashDate_ {
uint8_t month;
uint8_t day;
} FlashDate;
typedef struct FlashUserConfigData_ {
uint8_t version; // +0x000 (5=original retail)
uint8_t pad1; // +0x001
//ownerInfo
uint8_t favoriteColor; // +0x002
FlashDate birthday; // +0x003
uint8_t pad5; // +0x005
uint16_t nickname[10]; // +0x006
uint8_t nicknameLength; // +0x01A
uint8_t pad1B; // +0x01B
uint16_t comment[26]; // +0x01C
uint8_t commentLength; // +0x050
uint8_t pad51; // +0x051
//alarm
uint8_t alarmHour; // +0x052
uint8_t alarmMinute; // +0x053
uint8_t alarmSecond; // +0x054
uint8_t pad55; // +0x055
uint16_t alarmEnableWeek; // +0x056
//tp
uint16_t tp1; // +0x058
uint16_t tp2; // +0x05A
uint8_t tp3; // +0x05C
uint8_t tp4; // +0x05D
uint16_t tp5; // +0x05E
uint16_t tp6; // +0x060
uint8_t tp7; // +0x062
uint8_t tp8; // +0x063
//option
uint16_t language : 3; // +0x064
uint16_t gbaMode : 1;
uint16_t backlight : 2;
uint16_t autoboot : 1;
uint16_t pad64_4 : 4;
uint16_t hasFavoriteColor : 1;
uint16_t hasTpCalib : 1;
uint16_t hasLanguage : 1;
uint16_t hasRtc : 1;
uint16_t hasNickname : 1;
uint8_t timezone; // +0x066
uint8_t rtcClockAdjust; // +0x067
uint64_t rtcOffset; // +0x068
uint16_t saveCount; // +0x070
uint16_t crc; // +0x072
//extended settings
uint8_t exVersion; // +0x074
uint8_t exLanguage; // +0x075
uint16_t languages; // +0x076
unsigned char pad78[0x86]; // +0x078
uint16_t exCrc; // +0x0FE
} FlashUserConfigData;
#define FLASH_NCD_SIZE 0x74 // size of user config
#define FLASH_NCD_EX_SIZE 0x8C // size of extended portion of user config
typedef struct FlashConnection_ {
unsigned char ispID[32]; // +0x000
unsigned char ispPass[32]; // +0x020
unsigned char ssid[32]; // +0x040
unsigned char ssidAoss[32]; // +0x060
unsigned char wepKey[4][16]; // +0x080
uint32_t ipAddr; // +0x0C0
uint32_t gateway; // +0x0C4
uint32_t dns[2]; // +0x0C8
uint8_t subnetMask; // +0x0D0
unsigned char wepKey2[4][5]; // +0x0D1
uint8_t authType; // +0x0E5
uint8_t wepMode : 2; // +0x0E6 (0=None, 1=WEP 40, 2=WEP 104, 3=WEP 128)
uint8_t wepKeyNotation : 6; // +0x0E6 (0=hex, 1=ASCII)
uint8_t setType; // +0x0E7 (0=Manual, 1=AOSS, 2=Rakuraku, FF=unset)
uint8_t fieldE8; // +0x0E8 (TWL)
uint8_t fieldE9; // +0x0E9 (TWL)
uint16_t mtu; // +0x0EA (TWL)
unsigned char fieldEC[3]; // +0x0EC
uint8_t state; // +0x0EF
uint32_t dwcUserIdLo; // +0x0F0 DWC user ID (32) | 43-bit
uint16_t dwcUserIdHi : 11; // +0x0F4 DWC user ID (11) /
uint16_t dwcUnattestedUserIdLo : 5; // +0x0F4 DWC unattested user ID (5) | 43-bit
uint16_t dwcUnattestedUserIdMid1; // +0x0F6 DWC unattested user ID (16) |
uint16_t dwcUnattestedUserIdMid2; // +0x0F8 DWC unattested user ID (16) |
uint16_t dwcUnattestedUserIdHi : 6; // +0x0FA DWC unattested user ID (6) /
uint16_t pass : 10; // +0x0FA
uint16_t rand; // +0x0FC
uint16_t crc; // +0x0FE
} FlashConnSetting;
typedef struct FlashConnectionEx_ {
FlashConnSetting base; // +0x000
unsigned char psk[32]; // +0x100
unsigned char passphrase[64]; // +0x120
unsigned char field160[0x21]; // +0x160
uint8_t wpaMode; // +0x181 (0=No/WEP, 4=WPA TKIP, 5=WPA2 TKIP, 6=WPA AES, 7=WPA2 AES)
uint8_t proxyEnable; // +0x182
uint8_t proxyAuthenticate; // +0x183
char proxyName[48]; // +0x184
unsigned char field1B4[52]; // +0x1B4
uint16_t proxyPort; // +0x1E8
unsigned char field1EA[20]; // +0x1EA
uint16_t exCrc; // +0x1FE
} FlashConnExSetting;
// ----- Common routines
uint16_t ComputeCrc(const void *p, unsigned int length, uint16_t init);
uint16_t ComputeStaticCrc(const void *arm9Static, unsigned int arm9StaticSize, const void *arm7Static, unsigned int arm7StaticSize);
uint16_t ComputeSecondaryCrc(const void *arm9Secondary, unsigned int arm9SecondarySize, const void *arm7Secondary, unsigned int arm7SecondarySize);
void UpdateFirmwareModuleChecksums(unsigned char *buffer, unsigned int size);
// ----- RF routines
const char *GetRfType(int type);
int IsValidRfType(int type);
// ----- unpack routines
unsigned char *UncompressLZBlowfish(const unsigned char *buffer, unsigned int size, unsigned int romAddr, uint32_t *pSize, uint32_t *pUncompressed);
unsigned char *GetArm9StaticInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed);
unsigned char *GetArm7StaticInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed);
unsigned char *GetArm9SecondaryInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType);
unsigned char *GetArm7SecondaryInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType);
unsigned char *GetResourcesPackInfo(const unsigned char *buffer, unsigned int size, uint32_t *pRomAddr, uint32_t *pRamAddr, uint32_t *pSize, uint32_t *pUncompressed, CxCompressionType *pType);
void GetSecondaryResourceLoadAddresses(
const unsigned char *arm9Static,
unsigned int arm9StaticUncompressed,
const unsigned char *arm7Static,
unsigned int arm7StaticUncompressed,
uint32_t *pArm9SecondaryLoadAddr,
uint32_t *pArm7SecondaryLoadAddr,
uint32_t *pRsrcLoadAddr
);
int HasTwlSettings(int ipl2Type);
int HasExConfig(int ipl2Type);

184
src/fwutil.c Normal file
View File

@ -0,0 +1,184 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "compression.h"
#include "blowfish.h"
#include "firmware.h"
#include "cmd_common.h"
void CmdHelpQuit(void) {
puts("");
puts("Usage: quit");
puts("");
puts("Quits the program.");
}
void CmdProcQuit(int argc, const char **argv) {
(void) argc;
(void) argv;
DoExit();
}
typedef struct CmdProcEntry_ {
char *cmd;
void (*proc) (int argc, const char **argv);
} CmdProcEntry;
static CmdProcEntry sProcTable[] = {
{ "help", CmdProcHelp },
{ "h", CmdProcHelp },
{ "quit", CmdProcQuit },
{ "q", CmdProcQuit },
{ "exit", CmdProcQuit },
{ "load", CmdProcLoad },
{ "save", CmdProcSave },
{ "info", CmdProcInfo },
{ "verify", CmdProcVerify },
{ "map", CmdProcMap },
{ "compact", CmdProcCompact },
{ "md5", CmdProcMD5 },
{ "clean", CmdProcClean },
{ "restore", CmdProcRestore },
{ "fix", CmdProxFix },
{ "import", CmdProcImport },
{ "export", CmdProcExport },
{ "user", CmdProcUser },
{ "loc", CmdProcLoc },
{ "eb", CmdProcEB },
{ "db", CmdProcDB }
};
static void CmdParse(const char *buffer, int *pArgc, char ***pArgv) {
//empty command line?
if (*buffer == '\0' || *buffer == '\n' || *buffer == '\r') {
*pArgc = 0;
*pArgv = NULL;
return;
}
//count arguments
const char *p = buffer;
int quote = 0, nArg = 1, lastSpace = 0, nChars = 1;
while (1) {
char c = *(p++);
if (c == '\0' || c == '\n' || c == '\r') break;
int isWhiteSpace = (c == ' ' || c == '\t');
if (c == '"') {
quote = !quote;
} else if (isWhiteSpace && !quote) {
if (!lastSpace) {
nArg++;
nChars++; // null separator
}
} else {
nChars++; // character in string
}
lastSpace = isWhiteSpace;
}
//fill arguments
char **argv = (char **) calloc(nArg, sizeof(char *));
char *argbuf = (char *) calloc(nChars, 1);
char *argp = argbuf;
int curArgv = 0;
p = buffer;
lastSpace = 0;
quote = 0;
argv[curArgv++] = argp; // first argument
while (1) {
char c = *(p++);
if (c == '\0' || c == '\n' || c == '\r') {
if (!lastSpace) {
*(argp++) = '\0';
}
break;
}
int isWhiteSpace = (c == ' ' || c == '\t');
if (c == '"') {
quote = !quote;
} else if (isWhiteSpace && !quote) {
if (!lastSpace) {
//put terminator and append to argument list
*(argp++) = '\0';
if (curArgv < nArg) argv[curArgv++] = argp;
}
} else {
*(argp++) = c;
}
lastSpace = isWhiteSpace;
}
*pArgv = argv;
*pArgc = nArg;
}
static void CmdFree(char **argv) {
if (argv != NULL) {
free(argv[0]);
free(argv);
}
}
static void CmdDispatch(int argc, const char **argv) {
if (argc == 0) return;
for (unsigned int i = 0; i < sizeof(sProcTable) / sizeof(sProcTable[0]); i++) {
if (stricmp(sProcTable[i].cmd, argv[0]) == 0) {
if (sProcTable[i].proc != NULL) sProcTable[i].proc(argc, argv);
else puts("Unimplemented.");
return;
}
}
printf("Unrecognized command '%s'.\n", argv[0]);
}
static void CmdMain(const char *defpath) {
puts("*******************************************************************************");
puts("* *");
puts("* Nintendo DS Firmware Utility *");
puts("* *");
puts("*******************************************************************************");
puts("");
if (defpath != NULL) {
const char *loadargs[] = {
"load", defpath
};
CmdProcLoad(2, loadargs);
puts("");
}
puts("Type 'help' for a list of commands.");
puts("");
char buffer[1024];
while (!IsExiting()) {
printf("> ");
fgets(buffer, sizeof(buffer), stdin);
char **argv;
int argc;
CmdParse(buffer, &argc, &argv);
CmdDispatch(argc, argv);
CmdFree(argv);
puts("");
}
}
int main(int argc, char **argv) {
CmdMain(argc >= 1 ? argv[1] : NULL);
return 0;
}