# netmd-exploits

## What is it?
`netmd-exploits` is a library aiming to store all the available exploits for Sony NetMD devices.

## What exploits are available?

The exploits currently available are:

|        Exploit name        |                                                                       Firmware Versions* compatible                                                                             |    JavaScript class name    |
|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------|
|     Firmware Dumping       |                                                                            All versions supported                                                                               |        FirmwareDumper       |
|     USB Code Execution     |    S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R1.400, R1.300, R1.200, R1.100, R1.000, Hr1.000, Hn1.000, Hn1.100, Hn1.10A, Hn1.200, Hx1.070, Hx1.090, Hx1.0A0       |       USBCodeExecution      |
|           Tetris           |                                                           S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000                                                                |           Tetris            |
|     Force TOC Flushing     |                                        S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R1.400, R1.300, R1.200, R1.100, R1.000                                           |        ForcedTOCEdit        |
|       Upload SP Mono       |                                        S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R1.400, R1.300, R1.200, R1.100, R1.000                                           |        MonoSPUpload         |
| Atrac USB Control Transfer |                                        S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, ~~R1.400, R1.300, R1.200, R1.100, R1.000~~                                       | CachedSectorControlDownload |
|  Atrac USB No-RAM Transfer |                                        S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R1.400, R1.300, R1.200, R1.100, R1.000                                           |  CachedSectorNoRAMDownload  |
|  Atrac USB Bulk Transfer   |                                     S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, Hr1.000, Hn1.000, Hn1.100, Hn1.10A, Hn1.200                                         |   CachedSectorBulkDownload  |
|      SP Faster Upload      |                                                           S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000                                                                |        PCMFasterUpload      |
|        ATRAC1 Upload       |                                                           S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000                                                                |           SPUpload          |
|     EEprom Write Lock      |                                        S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R1.400, R1.300, R1.200, R1.100, R1.000                                           |       KillEepromWrite       |
|   Disc Spinning Notifier** |                                                     S1.600, S1.500, S1.400, S1.300, S1.200, S1.100, S1.000, R*, Hr*, Hn*                                                        |  WaitForDiscToStopSpinning  |
|   Unbounded memory access  |                                                                   Hr1.000, Hn1.000, Hn1.100, Hn1.10A, Hn1.200                                                                   |     HiMDUnboundedReading    |
|   HiMD USB Class Override  |                                                     Hr1.000, Hn1.000, Hn1.100, Hn1.10A, Hn1.200, Hx1.070, Hx1.090, Hx1.0A0                                                      |     HiMDUSBClassOverride    |

*The firmware versions listed here consist of the SOC type letter:

- R - CXD2677 (Type R)
- S - CXD2678 / CXD2680 (Type S)
- Hn - CXD2681 (gen1)
- Hr - CXD2681 (gen2)
- Hx - CXD2687

And the actual firmware version reported by the device.

**WaitForDiscToStopSpinning only supports Type-S devices, on Type-R and HiMD it always waits 10 seconds.

### Examples

|        Unit        |      SoC       |  Firmware version  |  netmd-exploits firmware version  |
|--------------------|----------------|--------------------|-----------------------------------|
|    Sony MZ-N510    |    CXD2680     |       1.600        |               S1.600              |
|    Sony MZ-N710    |    CXD2680     |       1.600        |               S1.600              |
|    Sony MZ-N1      |    CXD2677     |       1.200        |               R1.200              |
|    Sony MZ-N10     |    CXD2678     |       1.200        |               S1.300              |
|    Sony MZ-RH10    | CXD2681 (gen2) |       1.000        |              Hr1.000              |
|    Sony MZ-NH600   | CXD2681 (gen1) |       1.000        |              Hn1.000              |
|    Sony MZ-RH1     |    CXD2687     |       1.0A0        |              Hx1.0A0              |

## Hacking
If you would like to help with adding compatibility for your device, pull requests are welcome.

### An exploit's structure
The library keeps track of what exploits are compatible with what versions with the help of `src/compatibility.ts`.
Every exploit class has to inherit the `Exploit` abstract class. It provides multiple functions which make it easier to load the correct versions of exploits for every firmware version.
The constants that depend on the firmware version are stored in a `VersionStore` map returned from `getPropertyStore()`, from which it's possible to get values by calling `getProperty`, or by referencing their names in assembly code, prefixed with a '$'. Every exploit class has to also define a `static _name` const, used for compatibility checking.

### Loading and unloading exploits
Once an exploit is loaded using `ExploitStateManager.require` or `ExploitStateManager.envelop`, the exploit's `init()` method is called. Because of how exploits are loaded, exploits shouldn't
have their own constructor. Instead, `init()` should be used as an asynchronous constructor.

To unload an exploit you can use `ExploitStateManager.unload`. When using `ExploitStateManager.envelop`, this action will be done automatically.

When an exploit is unloaded, its `unload()` method is called, where the exploit can perform cleanup.
All behavior-modifying exploits should have a valid `unload()` method defined, in order to automatically restore the device to the default state.
If an exploit is using patches, the `unload()` method should clear the patches from the device, and then call `this.stateManager.freePatch()`, to mark the patch as unused.
All the patches for which `ExploitStateManager.freePatch()` wasn't called will automatically be unloaded from the device by the state manager.

If a patch is loaded by `ExploitStateManager.require`, and then reloaded again using `ExploitStateManager.envelop`, it will not be unloaded after returning from `envelop()`.
To unload it, `ExploitStateManager.unload` has to be called.

### The inbuilt assembler
The assembler has full support for macros (prefixed with '@'), `VersionStore` constants (prefixed with '$'), as well as variables, passed to the `assemble` function (prefixed with '%').

The macros available for every assembly program are stored in `src/assembler/core-macros.ts`.
Exploits can define private macros in the `_macros` property of the `VersionStore` returned from `getPropertyStore()`.

Happy hacking!

## Example

Below is an extremely basic example, which when run will download the first track from the disc onto the computer using the best suited exploit for it:
```ts
import { DevicesIds, openNewDevice } from 'netmd-js'
import { AtracRecovery, getBestSuited, ExploitStateManager } from 'netmd-exploits';
import { WebUSB } from 'usb';
import fs from 'fs';

(async() => {
    const usb = new WebUSB({ allowedDevices: DevicesIds, deviceTimeout: 1000000 });
    const dev = await openNewDevice(usb);
    const stateManager = await ExploitStateManager.create(dev!);

    const exploit = await stateManager.require(getBestSuited(AtracRecovery));
    fs.writeFileSync(await exploit.downloadTrack(0, console.log));
    await stateManager.unload(getBestSuited(AtracRecovery));

    process.exit(0);
})();
```

## Credits
The assembler built into `netmd-exploits` is a modified version of [keystone-js](https://github.com/AlexAltea/keystone.js) by AlexAltea
