mirror of
https://github.com/Garhoogin/fwutil.git
synced 2025-06-18 10:45:33 -04:00
Initial commit
This commit is contained in:
commit
92f609bf88
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
build.bat
|
||||
*.exe
|
||||
*.bin
|
||||
*.d
|
||||
*.nds
|
||||
*.elf
|
||||
*.srl
|
||||
*.map
|
||||
*.o
|
24
LICENSE
Normal file
24
LICENSE
Normal 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.
|
309
src/blowfish.c
Normal file
309
src/blowfish.c
Normal 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
24
src/blowfish.h
Normal 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
252
src/cmd_clean.c
Normal 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
149
src/cmd_common.c
Normal 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
84
src/cmd_common.h
Normal 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
121
src/cmd_compact.c
Normal 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
112
src/cmd_eb.c
Normal 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
386
src/cmd_export.c
Normal 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
169
src/cmd_fix.c
Normal 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
83
src/cmd_help.c
Normal 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
111
src/cmd_info.c
Normal 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
46
src/cmd_load.c
Normal 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
62
src/cmd_loc.c
Normal 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
119
src/cmd_map.c
Normal 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 = ®ions[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
204
src/cmd_ms5.c
Normal 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
266
src/cmd_user.c
Normal 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
106
src/cmd_verify.c
Normal 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
1480
src/compression.c
Normal file
File diff suppressed because it is too large
Load Diff
39
src/compression.h
Normal file
39
src/compression.h
Normal 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
426
src/firmware.c
Normal 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
219
src/firmware.h
Normal 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
184
src/fwutil.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user