1 (edited by reentrant 2025-03-18 20:31:00)

Hi,
New version of CDArchive is out with following new features:
- Automatic sector merging - no need to specify extrsectdir anymore (if specified, sectors will be dumped to the directory anyway)
- Automatic sector checking and repairing (both in the input image as well as those read by the drive) using ECC codes (RSPC). If a specific sector can be repaired (in the image) it is not read from the device.

List of removed dependencies:
- CDmage
- EccEdc

List of added dependencies:
- Python 3.12 - RS library - no C++ code available anywhere

Example command line:
CDArchive.exe --mode=ext --extrdrive=e --extrstart=100 --extrend=200 --extroverread=0 --extrskip=3 --extrdirection=f --extrdiscmode=cd --extrrefcue="d:\Storage\Sin\Sin.cue"

Example output:

Initialized C2 module
Extracting error range forward: 100 - 200
Repaired sector with C2: 150
Repaired sector with C2: 151
Repaired sector with C2: 152
Repaired sector with C2: 153
Repaired sector with C2: 154
Repaired sector with C2: 155
Repaired sector with C2: 156
Range direction result: 0 1

Extracted all sectors

Configuration:
- Install Python 3.12 (exactly this major version)
- Adjust PYTHONHOME variable in config file: Plugins\C2Corrector\C2Corrector.ini
- Copy python312.dll from Python installation directory to Plugins\C2Corrector directory

And that's it - no more tedious merging, fixing, checking...

Post's attachments

CDArchive.7z 350.04 kb, 2 downloads since 2025-03-18 

You don't have the permssions to download the attachments of this post.

2 (edited by reentrant 2025-03-18 21:23:59)

C2Corrector API (Plugins/C2Corrector/C2Corrector.DLL):

#pragma pack(push, 1)
typedef struct _C2_CORRECTOR_INIT {
    PVOID pythonEccP;
    PVOID pythonEccQ;
} C2_CORRECTOR_INIT, *PC2_CORRECTOR_INIT;
#pragma pack(pop)

// InitC2
typedef DWORD (WINAPI *pInitC2)(PC2_CORRECTOR_INIT c2InitBlock);

#pragma pack(push, 1)
typedef struct _C2_CORRECTOR_HANDLE {
    PVOID pythonEccP; // C2_CORRECTOR_INIT.pythonEccP
    PVOID pythonEccQ; // C2_CORRECTOR_INIT.pythonEccQ
    PUCHAR sectorData; // Length: 2352 bytes
    PUCHAR c2Pointers; // Length: 2352 / 8 bytes
    PUCHAR c2Repaired; // Length: 2352 / 8 bytes
} C2_CORRECTOR_HANDLE, *PC2_CORRECTOR_HANDLE;
#pragma pack(pop)

// HandleC2
typedef DWORD (WINAPI *pHandleC2)(PC2_CORRECTOR_HANDLE c2HandleBlock);

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

How it works:
ECC (ECCP / ECCQ) code inside data sector (mode 1 / mode 2) is in fact a Reed-Solomon code.
ECCP = RS(26,24) - difference = 2. It means 1 error can be corrected for a row of 26 bytes (or 2 positions without correcting).
ECCQ = RS(45,43) - difference = 2. It means 1 error can be a corrected for a row of 45 bytes (or 2 positions without correcting).

When you combine the RS algorithm with C2 pointers from the device and use the pointers as erasures it's possible to increase algorithm strength twice (2 errors can be corrected).

C2Corrector does just that - it uses C2 pointers as erasures (positions of invalid bytes) and tries to repair the data. Bytes that were repaired are recorded in c2Repaired buffer. This buffer should be combined with C2 buffer received from the device + appropriate repaired bytes should be replaced with data from sectorData buffer.

That's also how drives work internally. Depending on the manufacturer number of iterations varies (re-read + repair). Some are worse, some are better...

Hi reentrant, is this an alternative to DIC?

4 (edited by reentrant 2025-03-21 20:03:23)

Hi ssjkakaroto, no, it's just a brute-force tool to improve DIC's output...

While potentially useful having CDarchive  repair sectors as it extracts them sounds risky.

reentrant wrote:

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

If possible, please show me the sample code to call these func.

7 (edited by reentrant 2025-03-23 13:51:25)

Morlit wrote:

While potentially useful having CDarchive  repair sectors as it extracts them sounds risky.

Potentially yes, I only use it for hardcore cases like fetching more sectors from the rings...

sarami wrote:
reentrant wrote:

Steps:
1) Call InitC2 once in main
2) Call HandleC2 multiple times on each re-read

If possible, please show me the sample code to call these func.

DWORD C2Handler::corruptSectorForP(PC2_CORRECTOR_HANDLE c2HandleBlock, DWORD vectorNo, DWORD errorCount, BOOL enablePointers) {
    if(vectorNo >= 43)
        return ERROR_INVALID_PARAMETER;

    PUCHAR dataBuffer = c2HandleBlock->sectorData;
    
    errorCount = min(errorCount, 26);

    for(DWORD i = 0; i < errorCount; ++i) {
        DWORD dataIndex = userDataOffset + 2 * (43 * i + vectorNo) + 1;

        DEBUGPRINTWO(L"Corrupting P vector: 0x%03X: 0x%02X -> 0x%02X\n", dataIndex, dataBuffer[dataIndex], dataBuffer[dataIndex] + 1);

        ++dataBuffer[dataIndex];

        if(enablePointers && c2HandleBlock->c2Pointers) {
            PUCHAR c2Pointer = &c2HandleBlock->c2Pointers[dataIndex >> 3];
            *c2Pointer |= (0x1 << (dataIndex & 0x7));
        }
    }

    return 0;
}

DWORD C2Handler::corruptSectorForQ(PC2_CORRECTOR_HANDLE c2HandleBlock, DWORD vectorNo, DWORD errorCount, BOOL enablePointers) {
    if(vectorNo >= 26)
        return ERROR_INVALID_PARAMETER;

    PUCHAR dataBuffer = c2HandleBlock->sectorData;
    
    errorCount = min(errorCount, 43);

    for(DWORD i = 0; i < errorCount; ++i) {
        DWORD dataIndex = userDataOffset + 2 * ((43 * vectorNo + 44 * i) % 1118);

        DEBUGPRINTWO(L"Corrupting Q vector: 0x%03X: 0x%02X -> 0x%02X\n", dataIndex, dataBuffer[dataIndex], dataBuffer[dataIndex] + 1);

        ++dataBuffer[dataIndex];

        if(enablePointers && c2HandleBlock->c2Pointers) {
            PUCHAR c2Pointer = &c2HandleBlock->c2Pointers[dataIndex >> 3];
            *c2Pointer |= (0x1 << (dataIndex & 0x7));
        }
    }

    return 0;
}

#include "C2Handler.hpp"

#include <FileOps/FileOps.hpp>

DWORD WINAPI InitC2(PC2_CORRECTOR_INIT c2InitBlock) {
    return C2Handler::initC2(c2InitBlock);
}

DWORD WINAPI HandleC2(PC2_CORRECTOR_HANDLE c2HandleBlock) {
    return C2Handler::handleC2(c2HandleBlock);
}
#ifdef _DEBUG
int main() {
    C2_CORRECTOR_INIT c2InitBlock = {};

    DWORD retVal = InitC2(&c2InitBlock);
    if(!retVal) {
        UCHAR sectorData[2352];
        UCHAR c2Pointers[2352 / 8] = {};
        UCHAR c2Repaired[2352 / 8] = {};

        if(!(retVal = FileOps::readData(L"sector.data.in", sectorData, sizeof(sectorData)))) {
            C2_CORRECTOR_HANDLE c2HandleBlock = {};
            c2HandleBlock.pythonEccP = c2InitBlock.pythonEccP;
            c2HandleBlock.pythonEccQ = c2InitBlock.pythonEccQ;
            c2HandleBlock.sectorData = sectorData;
            c2HandleBlock.c2Pointers = c2Pointers;
            c2HandleBlock.c2Repaired = c2Repaired;

            //C2Handler::corruptSectorForP(&c2HandleBlock, 0, 2, FALSE);
            //retVal = HandleC2(&c2HandleBlock);

            //C2Handler::corruptSectorForP(&c2HandleBlock, 0, 3, TRUE);
            //retVal = HandleC2(&c2HandleBlock);

            C2Handler::corruptSectorForQ(&c2HandleBlock, 0, 2, TRUE);
            retVal = HandleC2(&c2HandleBlock);

            FileOps::writeData(L"sector.data.out", c2HandleBlock.sectorData, sizeof(sectorData));
            FileOps::writeData(L"sector.c2pre.out", c2HandleBlock.c2Pointers, sizeof(c2Pointers));
            FileOps::writeData(L"sector.c2post.out", c2HandleBlock.c2Repaired, sizeof(c2Repaired));
        }
    }

    return retVal ? EXIT_FAILURE : EXIT_SUCCESS;
}
#else
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
    return TRUE;
}
#endif

Keep in mind, when you pass c2Pointers bitmap, ECC algorithm will only repair bytes which are marked as 1 in C2 bitmap. If the repair is successful bits in c2Repaired bitmap will be set and it's up to you to merge c2Repaired bitmap + write appropriate bytes from sectorData into the image file...

reentrant wrote:

Configuration:
- Install Python 3.12 (exactly this major version)
- Adjust PYTHONHOME variable in config file: Plugins\C2Corrector\C2Corrector.ini
- Copy python312.dll from Python installation directory to Plugins\C2Corrector directory

Is python312.dll 64-bit only? Or does it work in 32bit dll? Are C2Corrector.dll and boost_python312-vc143-mt-x64-1_87.dll also 64bit only? It fails to load using LoadLibrary.