diff --git a/EDUReViver.suo b/EDUReViver.suo index ca165e4..9039a0b 100644 Binary files a/EDUReViver.suo and b/EDUReViver.suo differ diff --git a/EDUReViver/EDUReViver.manifest b/EDUReViver/EDUReViver.manifest new file mode 100644 index 0000000..bcd42f9 --- /dev/null +++ b/EDUReViver/EDUReViver.manifest @@ -0,0 +1,40 @@ + + + + EDUReViver for J-Link EDU + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EDUReViver/EDUReViver.vcxproj b/EDUReViver/EDUReViver.vcxproj index 5cdc8dc..6594f5d 100644 --- a/EDUReViver/EDUReViver.vcxproj +++ b/EDUReViver/EDUReViver.vcxproj @@ -104,6 +104,7 @@ true setupapi.lib;wininet.lib;shlwapi.lib;version.lib;crypt32.lib;ws2_32.lib;capstone_dll_d.lib;libcurld.lib;libeay32.lib;ssleay32.lib;%(AdditionalDependencies) + @@ -127,7 +128,6 @@ Level3 MaxSpeed true - true DENYCLONE;WIN32;NDEBUG;_CONSOLE;_STL70_;_STATIC_CPPLIB;%(PreprocessorDefinitions) @@ -170,6 +170,9 @@ + + + diff --git a/EDUReViver/EDUReViver.vcxproj.filters b/EDUReViver/EDUReViver.vcxproj.filters index 37f6000..87d6fe0 100644 --- a/EDUReViver/EDUReViver.vcxproj.filters +++ b/EDUReViver/EDUReViver.vcxproj.filters @@ -54,4 +54,9 @@ Header Files + + + Source Files + + \ No newline at end of file diff --git a/EDUReViver/configstore.cpp b/EDUReViver/configstore.cpp index bfec4f7..922694a 100644 --- a/EDUReViver/configstore.cpp +++ b/EDUReViver/configstore.cpp @@ -85,17 +85,24 @@ bool loadFirmwareConfigs(const wchar_t* cfgpath) } if (strstr(line, "//") == 0) { char version[0x71]; - char truefalse[0x71]; - char truefalse2[0x71]; + char issesstr[0x71]; + char regsstr[0x71]; patcher_config item = {0,}; - //"J-Link V10 compiled Feb 2 2018 18:12:40", 0x100840A0, 0x1A010718, 0x1A010EDA, false - int cnt = sscanf(line, "\"%[^\"]\", 0x%X, 0x%X, 0x%X, %[^,], %hhd, 0x%X, 0x%X, 0x%X, %[^,]", version, &item.sp, &item.lr, &item.usbrx, truefalse, &item.cmdReg, &item.R4, &item.R5, &item.R6, truefalse2); + //"J-Link V10 compiled Feb 2 2018 18:12:40", 0x100840A8, 0x1A010718, 0x1A010EDA, false + //"J-Link V11 compiled Dec 14 2022 09:09:01", 0x10081D18, 0x1A035B9A, 0x1A045899, true, 0, 0x0, 0x10080F80, 0x145 + int cnt = sscanf(line, "\"%[^\"]\", 0x%X, 0x%X, 0x%X, %[^,], %hhd, %[^\n]", version, &item.sptop, &item.lr, &item.usbrx, issesstr, &item.endgap, regsstr); if (cnt >= 5) { - truefalse[0x70] = 0; - truefalse2[0x70] = 0; + issesstr[0x70] = 0; + regsstr[0x70] = 0; version[0x70] = 0; - item.isSES = _stricmp(truefalse, "true") == 0; - item.nopad = _stricmp(truefalse2, "true") == 0; + item.isSES = _stricmp(issesstr, "true") == 0; + char* reg = strtok(regsstr, " ,"); + int i = 0; + while (reg) { + item.regs[i++] = strtol(reg, 0, 16); + reg = strtok(NULL, " ,"); + } + item.regCnt = i; g_patchercfgs.insert(std::make_pair(std::string(version), item)); } else { printf("Bad line in config file: %s\n", line); @@ -128,9 +135,12 @@ bool add_user_config(const char* fwversion, const patcher_config* config) char line[128]; int linelen; if (config->isSES) { - linelen = sprintf_s(line, _countof(line), "\"%s\", 0x%08X, 0x%08X, 0x%08X, true, %d, 0x%X, 0x%X, 0x%X, %s", version.c_str(), config->sp, config->lr, config->usbrx, config->cmdReg, config->R4, config->R5, config->R6, config->nopad?"true":"false"); + linelen = sprintf_s(line, _countof(line), "\"%s\", 0x%08X, 0x%08X, 0x%08X, true, %d", version.c_str(), config->sptop, config->lr, config->usbrx, config->endgap); + for (int i = 0; i < config->regCnt; i++) { + linelen += sprintf_s(&line[linelen], _countof(line)-linelen, ", 0x%X", config->regs[i]); + } } else { - linelen = sprintf_s(line, _countof(line), "\"%s\", 0x%08X, 0x%08X, 0x%08X, false", version.c_str(), config->sp, config->lr, config->usbrx); + linelen = sprintf_s(line, _countof(line), "\"%s\", 0x%08X, 0x%08X, 0x%08X, false", version.c_str(), config->sptop, config->lr, config->usbrx); } _write(fd, line, linelen); _close(fd); @@ -256,6 +266,8 @@ uint32_t extract_ldr_pool(const cs_insn* insn) typedef std::vector IntVec; void calc_stack(cs_insn *insn, size_t count, IntVec& vec); +void calc_call(cs_insn *insn, size_t count, IntVec& calls); +size_t guess_func_size(csh handle, const uint8_t *code, size_t maxsize, uint32_t address); #define FREE_AND_EXIT(ptr) cs_free(insn, count); cs_close(&handle); return ptr; @@ -319,9 +331,9 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) } cs_free(insn, count); // find __SEGGER_init_done - int retry = 0; + int ahead = 0; uint32_t mainaddr = 0; - while (retry++ < 20 && mainaddr == 0) { + while (ahead++ < 20 && mainaddr == 0) { uint32_t initfunc = reader.read_uint32_addr(inittable); inittable += 4; // SEGGER_crtinit_v7em_little.o @@ -351,7 +363,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) uint32_t taskstack = 0, stacksize = 0; uint32_t maintaskaddr = 0, taskstackinit = 0; for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64"\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + //printf("%08x\t%s\t\t%s\n", (uint32_t)insn[j].address, insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW) && arm->operands[0].type == ARM_OP_REG && arm->operands[1].type == ARM_OP_IMM) { if (arm->operands[0].reg == ARM_REG_R0) { @@ -386,7 +398,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) } } cs_free(insn, count); - //dispatchcmd是taskmain的一部分 + //dispatchcmd成为了taskmain的一部分 //1A0197AC 000 98 B0 SUB SP, SP, #0x60 //1A01B25A 060 80 47 BLX R0 count = cs_disasm(handle, reader.buf_at_addr(maintaskaddr & ~1), SESTASKMAINSIZE, (maintaskaddr & ~1), 0, &insn); @@ -394,14 +406,14 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) calc_stack(insn, count, spdvec); uint32_t cmdtable = 0; int cmdcnt = 0; - uint32_t r456val[3]; - bool r456dirty[3] = {true, true, true}; + uint32_t r456val[9]; + bool r456dirty[9] = {true, true, true, true, true, true, true, true, true}; int spd1, spd2; uint32_t dispatchlr; uint32_t usbrxbuf = 0; int rawCmdRegIdx = -1; for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // BLX R0 if (j > 5 && insn[j].id == ARM_INS_BLX && arm->operands[0].type == ARM_OP_REG) { @@ -411,48 +423,50 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) // base cmdtable // shift 2 if (insn[j-1].id == ARM_INS_LDR && prevarm->operands[0].reg == arm->operands[0].reg && - prevarm->operands[1].type == ARM_OP_MEM && prevarm->operands[1].shift.type == ARM_SFT_LSL && prevarm->operands[1].shift.value == 2) { - dispatchlr = (uint32_t)insn[j+1].address; - spd1 = spdvec[j]; - int cmdreg = prevarm->operands[1].mem.index; - int tablereg = prevarm->operands[1].mem.base; - j--; - // 寻找这对组合 - //ADDS R6, #0x65 - //UXTB R0, R6 - while (j--) { - cs_arm* arm = &insn[j].detail->arm; - cs_arm* prevarm = &insn[j-1].detail->arm; - if (insn[j].id == ARM_INS_UXTB && arm->operands[0].reg == cmdreg && - is_reg_add_imm(&insn[j-1], arm->operands[1].reg)) { - // R6=rawcmd - cmdcnt = prevarm->operands[1].imm; - printf("rawcmd reg: %s, val: %08X\n", cs_reg_name(handle, prevarm->operands[0].reg), cmdcnt + 0xE0); - rawCmdRegIdx = prevarm->operands[0].reg - ARM_REG_R0; - break; - } + prevarm->operands[1].type == ARM_OP_MEM && prevarm->operands[1].shift.type == ARM_SFT_LSL && prevarm->operands[1].shift.value == 2) + { + dispatchlr = (uint32_t)insn[j+1].address; + spd1 = spdvec[j]; + int cmdreg = prevarm->operands[1].mem.index; + int tablereg = prevarm->operands[1].mem.base; + j--; + // 寻找这对组合 + //ADDS R6, #0x65 + //UXTB R0, R6 + while (j--) { + cs_arm* arm = &insn[j].detail->arm; + cs_arm* prevarm = &insn[j-1].detail->arm; + if (insn[j].id == ARM_INS_UXTB && arm->operands[0].reg == cmdreg && + is_reg_add_imm(&insn[j-1], arm->operands[1].reg)) + { + // R6=rawcmd + cmdcnt = prevarm->operands[1].imm; + printf("rawcmd reg: %s, val: %08X\n", cs_reg_name(handle, prevarm->operands[0].reg), cmdcnt + 0xE0); + rawCmdRegIdx = prevarm->operands[0].reg - ARM_REG_R0; + break; } - while (j++) { - //MOV R1, #g_usbcmds - cs_arm* arm = &insn[j].detail->arm; - if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW) && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == tablereg && arm->operands[1].type == ARM_OP_IMM) { - cmdtable = arm->operands[1].imm; - } - if (insn[j].id == ARM_INS_MOVT && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == tablereg && arm->operands[1].type == ARM_OP_IMM) { - *((uint16_t*)&cmdtable + 1) = arm->operands[1].imm; - break; - } + } + while (j++) { + //MOV R1, #g_usbcmds + cs_arm* arm = &insn[j].detail->arm; + if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW) && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == tablereg && arm->operands[1].type == ARM_OP_IMM) { + cmdtable = arm->operands[1].imm; } - if (cmdcnt && cmdtable) { - printf("g_usbcmds: %08X, count: %d\n", cmdtable, cmdcnt); + if (insn[j].id == ARM_INS_MOVT && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == tablereg && arm->operands[1].type == ARM_OP_IMM) { + *((uint16_t*)&cmdtable + 1) = arm->operands[1].imm; break; } + } + if (cmdcnt && cmdtable) { + printf("g_usbcmds: %08X, count: %d\n", cmdtable, cmdcnt); + break; + } } // lookup usbdfuncs table later } // 跟踪出现的目的R4~R6赋值 const char* unknown = 0; - if (arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg >= ARM_REG_R4 && arm->operands[0].reg <= ARM_REG_R6) { + if (arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg >= ARM_REG_R4 && arm->operands[0].reg <= ARM_REG_R12) { // 持续跟踪R4/R5/R6的MOVW/MOVT对值 uint32_t* lpreg = &r456val[arm->operands[0].reg - ARM_REG_R4]; bool* lpdirty = &r456dirty[arm->operands[0].reg - ARM_REG_R4]; @@ -485,7 +499,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) } #ifdef _DEBUG if (unknown) { - //printf("Unsupported %s %"PRIx64" %03x \t%s\t\t%s\n", unknown, insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("Unsupported %s %08x %03x \t%s\t\t%s\n", unknown, (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); } #endif } @@ -493,161 +507,171 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) #define r4val r456val[0] #define r5val r456val[1] #define r6val r456val[2] - printf("R4: %08X R5:%08X R6:%08X\n", r4val, r5val, r6val); + printf("R4: %08X R5: %08X R6: %08X\n", r4val, r5val, r6val); if (cmdcnt == 0) { errprintf("Analyst failed on command table!\n"); cs_close(&handle); return NULL; } uint32_t cmde0func = reader.read_uint32_addr(cmdtable + (cmdcnt - 1 - (0xFF - 0xE0)) * 4); - printf("cmd_e0_fine_write_read: %08X\n", cmde0func); + size_t e0size = guess_func_size(handle, reader.buf_at_addr(cmde0func & ~1), 0x70, (cmde0func & ~1)); + printf("cmd_e0_fine_write_read: %08X, %X bytes\n", cmde0func, e0size); // 寻找usbrxbuf崩溃点, 5C - count = cs_disasm(handle, reader.buf_at_addr(cmde0func & ~1), 0x70, (cmde0func & ~1), 0, &insn); + count = cs_disasm(handle, reader.buf_at_addr(cmde0func & ~1), e0size, (cmde0func & ~1), 0, &insn); calc_stack(insn, count, spdvec); - int callcount = 0; - size_t firstBL = -1, firstBLX = -1, secondBLX = -1; - int funcsreg, blxrxreg; - uint32_t currstack; - bool smallstack = false; - for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); - cs_arm* arm = &insn[j].detail->arm; - // BLX R2 - if (insn[j].id == ARM_INS_BL && arm->operands[0].type == ARM_OP_IMM) { - firstBL = j; + // 第一次call是settimer(-1), 第二次是usbrx(arg,12), 第三次是usbrx(writebuf,writelen) + // 第二可能不内联, 第三可能跟if(writelen)条件一起外联为usbrxif + // 考虑可能分开内外联, 不能限制两次rx寄存器/地址 + IntVec calls; + calc_call(insn, count, calls); + if (calls.size() < 5) { + errprintf("unexpected cmd_e0_fine_write_read calls count: %u.\n", calls.size()); + FREE_AND_EXIT(NULL); + } + size_t firstcall = calls[0], firstrx = calls[1], secondrx = calls[2]; + uint32_t argspdelta, savedregs, endgap; + bool rxaddrknown = (insn[firstrx].id == ARM_INS_BL || insn[secondrx].id == ARM_INS_BL); + uint32_t argstack; + for (size_t i = 0; i < count; i++) { + cs_arm* arm = &insn[i].detail->arm; + if (i < firstcall) { + if (insn[i].id == ARM_INS_PUSH && arm->operands[arm->op_count-1].reg == ARM_REG_LR) { + savedregs = arm->op_count - 1; + } } - if (firstBL != -1 && insn[j].id == ARM_INS_MOVT) { - funcsreg = arm->operands[0].reg; + if (i < firstrx) { + if (insn[i].id == ARM_INS_MOV && arm->op_count == 2 && arm->operands[1].type == ARM_OP_REG && arm->operands[1].reg == ARM_REG_SP) { + argspdelta = 0; + } + if (insn[i].id == ARM_INS_ADD && arm->op_count == 3 && arm->operands[1].type == ARM_OP_REG && arm->operands[1].reg == ARM_REG_SP) { + argspdelta = arm->operands[2].imm; + } } - if (insn[j].id == ARM_INS_BLX && arm->operands[0].type == ARM_OP_REG) { - if (callcount) { - spd2 = spdvec[j]; - secondBLX = j; - blxrxreg = arm->operands[0].reg; - currstack = taskstackinit + spd1 + spd2; - printf("sp: %08X dispatch LR:%08X\n", currstack, dispatchlr); + if (i == secondrx) { + spd2 = spdvec[i]; // -30~-40 + argstack = taskstackinit + spd1 + spd2 + argspdelta; + endgap = (-spd2) - (savedregs + 1)*4 - 0x30 - argspdelta; + printf("argstack: %08X original LR: %08X, endgap: %d\n", argstack, dispatchlr, endgap); + } + } + if (rxaddrknown) { + usbrxbuf = insn[(insn[firstrx].id == ARM_INS_BL)?firstrx:secondrx].detail->arm.operands[0].imm; + } else { + int funcsreg, blxrxreg = insn[firstrx].detail->arm.operands[0].reg; + // first movw/movt before firstrx call + for (size_t i = 0; i < firstrx; i++) { + if (insn[i].id == ARM_INS_MOVT) { + funcsreg = insn[i].detail->arm.operands[0].reg; break; - } else { - firstBLX = j; - callcount++; } } - // V12固件优化最小栈 0C+10+14 - if (insn[j].id == ARM_INS_SUB && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == ARM_REG_SP && arm->operands[1].type == ARM_OP_IMM) { - smallstack = (arm->operands[1].imm <= 0x30); + // 寻找指针源, 以便后面回溯指针赋值 + uint32_t pipefuncs; + int midreg = ARM_REG_INVALID, basereg = ARM_REG_INVALID; + int rxdisp; + for (size_t j = firstcall+1; j < firstrx; j++) { + cs_arm* arm = &insn[j].detail->arm; + if (midreg == ARM_REG_INVALID) { + // MOV32 R6, #g_usbd_funcs + if (arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == funcsreg && arm->operands[1].type == ARM_OP_IMM) { + if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW)) { + pipefuncs = arm->operands[1].imm; + } else if (insn[j].id == ARM_INS_MOVT) { + *((uint16_t*)&pipefuncs + 1) = arm->operands[1].imm; + printf("g_pipe_funcs: %08X\n", pipefuncs); + midreg = arm->operands[0].reg; + } + } + } else if (basereg == ARM_REG_INVALID) { + if (insn[j].id == ARM_INS_LDR && + arm->operands[0].type == ARM_OP_REG && + arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.base == midreg && arm->operands[1].mem.disp == 0) + { + // LDR R0, [R6] + basereg = arm->operands[0].reg; + } + } else if (insn[j].id == ARM_INS_LDR && + arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == blxrxreg && + arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.base == basereg) + { + // LDR R2, [R0,#8] + rxdisp = arm->operands[1].mem.disp; + break; + } } - } - // 寻找指针源 - uint32_t pipefuncs; - int midreg = ARM_REG_INVALID, basereg = ARM_REG_INVALID; - int rxdisp; - for (size_t j = firstBL+1; j < firstBLX; j++) { - cs_arm* arm = &insn[j].detail->arm; - if (midreg == ARM_REG_INVALID) { - // MOV32 R6, #g_usbd_funcs - if (arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == funcsreg && arm->operands[1].type == ARM_OP_IMM) { + // 求得cmd_e0_fine_write_read最后的发送 + uint32_t usbtxbuf = insn[calls.back()].detail->arm.operands[0].imm; + printf("usbtxbuf: %08X\n", usbtxbuf); + cs_free(insn, count); + // 在apptaskmain里寻找对usbdfuncs的赋值, 假设第一个是对的 + //ROM:1A019116 0B0 MOV R0, #g_usbd_funcs + //ROM:1A01911E 0B0 MOV R1, #usbdfuncs + //ROM:1A019126 0B0 STR R1, [R0] + count = cs_disasm(handle, reader.buf_at_addr(maintaskaddr & ~1), SESTASKMAINSIZE, (maintaskaddr & ~1), 0, &insn); + uint32_t r0val, r1val; + for (size_t j = 0; j < count - 1; j++) { + //printf("%08x\t%s\t\t%s\n", (uint32_t)insn[j].address, insn[j].mnemonic, insn[j].op_str); + cs_arm* arm = &insn[j].detail->arm; + if (arm->operands[1].type == ARM_OP_IMM && arm->operands[0].type == ARM_OP_REG && (arm->operands[0].reg == ARM_REG_R0 || arm->operands[0].reg == ARM_REG_R1)) { if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW)) { - pipefuncs = arm->operands[1].imm; + (arm->operands[0].reg == ARM_REG_R0?r0val:r1val) = arm->operands[1].imm; } else if (insn[j].id == ARM_INS_MOVT) { - *((uint16_t*)&pipefuncs + 1) = arm->operands[1].imm; - printf("g_pipe_funcs: %08X\n", pipefuncs); - midreg = arm->operands[0].reg; - } + *((uint16_t*)(arm->operands[0].reg == ARM_REG_R0?&r0val:&r1val) + 1) = arm->operands[1].imm; + } } - } else if (basereg == ARM_REG_INVALID) { - if (insn[j].id == ARM_INS_LDR && - arm->operands[0].type == ARM_OP_REG && - arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.base == midreg && arm->operands[1].mem.disp == 0) + if (insn[j].id == ARM_INS_STR && + arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == ARM_REG_R1 && + arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.disp == 0 && arm->operands[1].mem.base == ARM_REG_R0 && r0val == pipefuncs) { - // LDR R0, [R6] - basereg = arm->operands[0].reg; - } - } else if (insn[j].id == ARM_INS_LDR && - arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == blxrxreg && - arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.base == basereg) - { - // LDR R2, [R0,#8] - rxdisp = arm->operands[1].mem.disp; - break; - } - } - // 寻找cmd_e0_fine_write_read最后的发送 - uint32_t usbtxbuf; - for (size_t j = secondBLX+1; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); - if (insn[j].id == ARM_INS_BL && insn[j].detail->arm.operands[0].type == ARM_OP_IMM) { - usbtxbuf = insn[j].detail->arm.operands[0].imm; - } - if (spdvec[j] == 0) { - printf("usbtxbuf: %08X\n", usbtxbuf); - break; - } - } - cs_free(insn, count); - // 在apptaskmain里寻找对usbdfuncs的赋值, 假设第一个是对的 - //ROM:1A019116 0B0 MOV R0, #g_usbd_funcs - //ROM:1A01911E 0B0 MOV R1, #usbdfuncs - //ROM:1A019126 0B0 STR R1, [R0] - count = cs_disasm(handle, reader.buf_at_addr(maintaskaddr & ~1), SESTASKMAINSIZE, (maintaskaddr & ~1), 0, &insn); - uint32_t r0val, r1val; - for (size_t j = 0; j < count - 1; j++) { - //printf("%"PRIx64"\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); - cs_arm* arm = &insn[j].detail->arm; - if (arm->operands[1].type == ARM_OP_IMM && arm->operands[0].type == ARM_OP_REG && (arm->operands[0].reg == ARM_REG_R0 || arm->operands[0].reg == ARM_REG_R1)) { - if ((insn[j].id == ARM_INS_MOV || insn[j].id == ARM_INS_MOVW)) { - (arm->operands[0].reg == ARM_REG_R0?r0val:r1val) = arm->operands[1].imm; - } else if (insn[j].id == ARM_INS_MOVT) { - *((uint16_t*)(arm->operands[0].reg == ARM_REG_R0?&r0val:&r1val) + 1) = arm->operands[1].imm; - } - } - if (insn[j].id == ARM_INS_STR && - arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == ARM_REG_R1 && - arm->operands[1].type == ARM_OP_MEM && arm->operands[1].mem.disp == 0 && arm->operands[1].mem.base == ARM_REG_R0 && r0val == pipefuncs) - { - uint32_t rxbeginaddr = reader.read_uint32_addr(r1val + rxdisp); - cs_insn* ins2; - size_t cnt2 = cs_disasm(handle, reader.buf_at_addr(rxbeginaddr & ~1), 0x100, (rxbeginaddr & ~1), 0, &ins2); - bool hitted = false; - for (size_t j = 0; j < cnt2 - 1; j++) { + uint32_t rxbeginaddr = reader.read_uint32_addr(r1val + rxdisp); + cs_insn* ins2; + size_t cnt2 = cs_disasm(handle, reader.buf_at_addr(rxbeginaddr & ~1), 0x100, (rxbeginaddr & ~1), 0, &ins2); + bool hitted = false; + for (size_t j = 0; j < cnt2 - 1; j++) { #ifdef _DEBUG - printf("%"PRIx64"\t%s\t\t%s\n", ins2[j].address, ins2[j].mnemonic, ins2[j].op_str); + printf("%08x\t%s\t\t%s\n", (uint32_t)ins2[j].address, ins2[j].mnemonic, ins2[j].op_str); #endif - cs_arm* arm = &ins2[j].detail->arm; - //ROM:1A0458B0 MOVW R3, #3000 - //ROM:1A0458B4 BL sub_1A0410A0 - if (ins2[j].id == ARM_INS_MOVW && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == ARM_REG_R3 && - arm->operands[1].type == ARM_OP_IMM && arm->operands[1].imm == 3000 && - ins2[j+1].id == ARM_INS_BL) - { - usbrxbuf = reader.read_uint32_addr(r1val + rxdisp); // TODO: use dispatch from fine_read_write - printf("usbrxbuf: %08X\n", usbrxbuf); - hitted = true; + cs_arm* arm = &ins2[j].detail->arm; + //ROM:1A0458B0 MOVW R3, #3000 + //ROM:1A0458B4 BL sub_1A0410A0 + if (ins2[j].id == ARM_INS_MOVW && arm->operands[0].type == ARM_OP_REG && arm->operands[0].reg == ARM_REG_R3 && + arm->operands[1].type == ARM_OP_IMM && arm->operands[1].imm == 3000 && + ins2[j+1].id == ARM_INS_BL) + { + usbrxbuf = reader.read_uint32_addr(r1val + rxdisp); // TODO: use dispatch from fine_read_write + printf("usbrxbuf: %08X\n", usbrxbuf); + hitted = true; + break; + } + } + cs_free(ins2, cnt2); + if (hitted) { break; } } - cs_free(ins2, cnt2); - if (hitted) { - break; - } } } cs_free(insn, count); // version, sp, lr, uxbrx, true, cmdReg, R4, R5, R6 - if (rawCmdRegIdx >= 4 && rawCmdRegIdx <= 6) { + if (rawCmdRegIdx >= 4 && rawCmdRegIdx <= 12) { r456val[rawCmdRegIdx - 4] = cmdcnt + 0xE0; r456dirty[rawCmdRegIdx - 4] = false; } - for (int i = 0; i < 3; i++) { + bool fatal = false; + for (size_t i = 0; i < savedregs; i++) { if (r456dirty[i]) { errprintf("R%d val is bad!\n", 4 + i); + if (i != rawCmdRegIdx - 4) { + fatal = true; + } } } - if (r456dirty[0] || r456dirty[1] || r456dirty[2]) { + if (fatal) { cs_close(&handle); return NULL; } - //printf("\"%s\", 0x%08X, 0x%08X, 0x%08X, true, %d, 0x%X, 0x%X, 0x%X\n", reader.get_banner(), currstack, dispatchlr, usbrxbuf, rawCmdRegIdx, r4val, r5val, r6val); - patcher_config item = {currstack, dispatchlr, usbrxbuf, true, (char)rawCmdRegIdx, r4val, r5val, r6val, smallstack}; + patcher_config item = {argstack, dispatchlr, usbrxbuf, true, (char)savedregs}; + memcpy(item.regs, r456val, sizeof(uint32_t)*savedregs); add_user_config(reader.get_banner(), &item); } // IAR固件? @@ -657,13 +681,13 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) startaddr = reader.read_uint32_addr(startaddr); printf("__iar_program_start: %08X\n", startaddr); } else { - printf("Firmware not build by EWARM\n"); + errprintf("Firmware not build by EWARM\n"); FREE_AND_EXIT(NULL); } cs_free(insn, count); count = cs_disasm(handle, reader.buf_at_addr((startaddr & ~1) + 8), 4, (startaddr & ~1) + 8, 0, &insn); if (count <= 0 || insn[0].id != ARM_INS_BL) { - printf("Firmware not build by EWARM.\n"); + errprintf("Firmware not build by EWARM.\n"); FREE_AND_EXIT(NULL); } uint32_t __cmainaddr = insn[0].detail->arm.operands[0].imm; @@ -692,7 +716,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) uint32_t maintaskaddr = -1, taskstackinit = -1; int step = 0; for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // LDR R3, =(app_maintask+1) if (step == 0 && insn[j].id == ARM_INS_LDR && @@ -707,7 +731,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) bool stackok = false, sizeok = false; int stackreg = ARM_REG_INVALID, sizereg = ARM_REG_INVALID; while(j--) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // 先找[SP]和[SP+4]填充stackreg和sizereg // STR R1, [SP,#0x10+StackSize] @@ -758,7 +782,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) uint32_t target = -1; int spd1, spd2, spd3; for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // LDRB.W R0, [SP,#8+cmd] if (step == 0 && insn[j].id == ARM_INS_LDRB && @@ -786,7 +810,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) uint32_t dispatchlr, cmdtable; int cmdcnt = 0; for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // BLX R0 if (insn[j].id == ARM_INS_BLX && arm->operands[0].type == ARM_OP_REG) { @@ -796,7 +820,7 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) int reg = ARM_REG_INVALID; // 往回寻找ADD/LDR while (j--) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); cs_arm* arm = &insn[j].detail->arm; // V10/V9会有不同的寻址指令 // ADR.W R0, g_usb_cmdtable @@ -835,46 +859,41 @@ const patcher_config* analyst_firmware_stack(const void* fwbuf, size_t fwlen) cs_close(&handle); return NULL; } - uint32_t cmde0func = reader.read_uint32_addr(cmdtable + (cmdcnt - 1 - (0xFF - 0xE0)) * 4); + uint32_t cmde0func = reader.read_uint32_addr(cmdtable + (cmdcnt - 1 - (0xFF - 0xE0)) * 4); // e0肯定第二段 printf("cmd_e0_fine_write_read: %08X\n", cmde0func); // 寻找usbrxbuf崩溃点, 4c - count = cs_disasm(handle, reader.buf_at_addr(cmde0func & ~1), 0x60, (cmde0func & ~1), 0, &insn); - calc_stack(insn, count, spdvec); - uint32_t usbrxbuf = -1; - size_t prevj = -1; - uint32_t currstack; - for (size_t j = 0; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); - cs_arm* arm = &insn[j].detail->arm; - // BL app_usbrxbuf - if (insn[j].id == ARM_INS_BL && arm->operands[0].type == ARM_OP_IMM) { - if (arm->operands[0].imm == usbrxbuf) { - spd3 = spdvec[j]; - currstack = taskstackinit + spd1 + spd2 + spd3; - printf("sp: %08X dispatch LR:%08X usbrxbuf: %08X\n", currstack, dispatchlr, usbrxbuf); - prevj = j; - break; - } else { - usbrxbuf = arm->operands[0].imm; - } - } - } - // 寻找cmd_e0_fine_write_read最后的发送 - uint32_t usbtxbuf; - for (size_t j = prevj + 1; j < count; j++) { - //printf("%"PRIx64" %03x \t%s\t\t%s\n", insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); - if (insn[j].id == ARM_INS_BL && insn[j].detail->arm.operands[0].type == ARM_OP_IMM) { - usbtxbuf = insn[j].detail->arm.operands[0].imm; - } - if (spdvec[j] == 0) { - printf("usbtxbuf: %08X\n", usbtxbuf); - break; - } + size_t e0size = guess_func_size(handle, reader.buf_at_addr(cmde0func & ~1), 0x60, (cmde0func & ~1)); + count = cs_disasm(handle, reader.buf_at_addr(cmde0func & ~1), e0size, (cmde0func & ~1), 0, &insn); + IntVec calls; + calc_call(insn, count, calls); + if (calls.size() < 5) { + errprintf("unexpected cmd_e0_fine_write_read calls count: %u.\n", calls.size()); + FREE_AND_EXIT(NULL); } + calc_stack(insn, count, spdvec); + size_t firstrx = calls[1], secondrx = calls[2]; + uint32_t usbrxbuf = insn[firstrx].detail->arm.operands[0].imm; + spd3 = spdvec[secondrx]; + int argspdelta = -1; + for (size_t i = 0; i < firstrx; i++) { + //printf("%08x %03x \t%s\t\t%s\n", (uint32_t)insn[j].address, -spdvec[j], insn[j].mnemonic, insn[j].op_str); + cs_arm* arm = &insn[i].detail->arm; + if (insn[i].id == ARM_INS_MOV && arm->op_count == 2 && arm->operands[1].type == ARM_OP_REG && arm->operands[1].reg == ARM_REG_SP) { + argspdelta = 0; + } + if (insn[i].id == ARM_INS_ADD && arm->op_count == 3 && arm->operands[1].type == ARM_OP_REG && arm->operands[1].reg == ARM_REG_SP) { + argspdelta = arm->operands[2].imm; + } + } + uint32_t argstack = taskstackinit + spd1 + spd2 + spd3 + argspdelta; + printf("argstack: %08X original LR:%08X usbrxbuf: %08X\n", argstack, dispatchlr, usbrxbuf); + // 求得cmd_e0_fine_write_read最后的发送 + uint32_t usbtxbuf = insn[calls.back()].detail->arm.operands[0].imm; + printf("usbtxbuf: %08X\n", usbtxbuf); cs_free(insn, count); // version, sp, lr, uxbrx, false //printf("\"%s\", 0x%08X, 0x%08X, 0x%08X, false\n", reader.get_banner(), currstack, dispatchlr, usbrxbuf); - patcher_config item = {currstack, dispatchlr, usbrxbuf, false}; + patcher_config item = {argstack, dispatchlr, usbrxbuf, false}; add_user_config(reader.get_banner(), &item); } cs_close(&handle); @@ -886,27 +905,79 @@ void calc_stack(cs_insn *insn, size_t count, IntVec& vec) { int spd = 0; vec.resize(count); - for (size_t j = 0; j < count; j++) { - vec[j] = spd; - if (insn[j].id == ARM_INS_PUSH) { - spd -= insn[j].detail->arm.op_count * 4; + for (size_t i = 0; i < count; i++) { + vec[i] = spd; + if (insn[i].id == ARM_INS_PUSH) { + spd -= insn[i].detail->arm.op_count * 4; } - if (insn[j].id == ARM_INS_POP) { - spd += insn[j].detail->arm.op_count * 4; + if (insn[i].id == ARM_INS_POP) { + spd += insn[i].detail->arm.op_count * 4; } // ldr lr,[sp],#4 - if (insn[j].id == ARM_INS_LDR && insn[j].detail->arm.op_count == 3 && - insn[j].detail->arm.operands[1].type == ARM_OP_MEM && insn[j].detail->arm.operands[1].mem.base == ARM_REG_SP && - insn[j].detail->arm.operands[2].type == ARM_OP_IMM) { - spd += insn[j].detail->arm.operands[2].imm; - } - if ((insn[j].id == ARM_INS_SUB || insn[j].id == ARM_INS_ADD) && insn[j].detail->arm.op_count == 2 && insn[j].detail->arm.operands[0].type == ARM_OP_REG && insn[j].detail->arm.operands[0].reg == ARM_REG_SP) { - if (insn[j].id == ARM_INS_SUB) { - spd -= insn[j].detail->arm.operands[1].imm; + if (insn[i].id == ARM_INS_LDR && insn[i].detail->arm.op_count == 3 && + insn[i].detail->arm.operands[1].type == ARM_OP_MEM && insn[i].detail->arm.operands[1].mem.base == ARM_REG_SP && + insn[i].detail->arm.operands[2].type == ARM_OP_IMM) { + spd += insn[i].detail->arm.operands[2].imm; + } + if ((insn[i].id == ARM_INS_SUB || insn[i].id == ARM_INS_ADD) && insn[i].detail->arm.op_count == 2 && insn[i].detail->arm.operands[0].type == ARM_OP_REG && insn[i].detail->arm.operands[0].reg == ARM_REG_SP) { + if (insn[i].id == ARM_INS_SUB) { + spd -= insn[i].detail->arm.operands[1].imm; } else { - spd += insn[j].detail->arm.operands[1].imm; + spd += insn[i].detail->arm.operands[1].imm; } } } } +void calc_call(cs_insn *insn, size_t count, IntVec& calls) +{ + for (size_t i = 0; i < count; i++) { + if (insn[i].id == ARM_INS_BL && insn[i].detail->arm.operands[0].type == ARM_OP_IMM) { + calls.push_back(i); + } + if (insn[i].id == ARM_INS_BLX && insn[i].detail->arm.operands[0].type == ARM_OP_REG) { + calls.push_back(i); + } + // tail jumpout + if (insn[i].id == ARM_INS_B && i == count - 1) { + calls.push_back(i); + } + } +} + +size_t guess_func_size(csh handle, const uint8_t *code, size_t maxsize, uint32_t address) +{ + size_t funcsize = 0; + cs_insn* insn; + size_t count = cs_disasm(handle, code, maxsize, address, 0, &insn); + bool endonpop = false; + for (size_t i = 0; i < count; i++) { + if (insn[i].id == ARM_INS_PUSH && endonpop == false) { + for (uint8_t j = 0; j < insn[i].detail->arm.op_count; j++) { + if (insn[i].detail->arm.operands[j].reg == ARM_REG_LR) { + endonpop = true; + break; + } + } + } + bool hitted = false; + // quick n dirty + if (insn[i].id == ARM_INS_POP && endonpop) { + for (uint8_t j = 0; j < insn[i].detail->arm.op_count; j++) { + if (insn[i].detail->arm.operands[j].reg == ARM_REG_PC) { + hitted = true; + break; + } + } + } + if (insn[i].id == ARM_INS_BLX && endonpop == false && insn[i].detail->arm.operands[0].reg == ARM_REG_LR) { + hitted = true; + } + if (hitted) { + funcsize = (uint32_t)insn[i].address + insn[i].size - address; + break; + } + } + cs_free(insn, count); + return funcsize; +} diff --git a/EDUReViver/configstore.h b/EDUReViver/configstore.h index 50ea2f9..3ecf8df 100644 --- a/EDUReViver/configstore.h +++ b/EDUReViver/configstore.h @@ -6,13 +6,14 @@ struct patcher_config { //const char* version; - uint32_t sp; // λк͸λ - uint32_t lr; // dispatchcmdִ + uint32_t sptop; // λк͸λ(fineargͷ) + uint32_t lr; // ԭLR, ԭusbcmdּ uint32_t usbrx; - bool isSES; // SESҪʹR4-R6ֵ - char cmdReg; // ʹõļĴ - uint32_t R4, R5, R6; - bool nopad; // ջĩβû4ֽڿն + bool isSES; // SESҪʹR4-R6ֵ + uint8_t regCnt; // ⱣļĴ(LR) + //char cmdReg; // ʹõļĴ + uint32_t regs[9]; // R4-R6ֵ, ԤR12 + uint8_t endgap; // ջβն(IAR, SESﲻ) }; tm get_build_date(const char* version); diff --git a/EDUReViver/main.cpp b/EDUReViver/main.cpp index cebc198..2aa4423 100644 --- a/EDUReViver/main.cpp +++ b/EDUReViver/main.cpp @@ -21,6 +21,7 @@ uint32_t encode_fwLen(uint32_t fwlen); uint16_t crc16_kermit(const uint8_t *buf, size_t len); uint32_t calc_sn_checksum(uint32_t sn); uint32_t crc32_rev(uint8_t *buf, size_t len); +bool sha1(const void* buff, size_t buflen, void* digest); // check bool is_BTL_version(const char* fwversion); bool is_offical_bootloader(const void* btl); @@ -64,7 +65,7 @@ cmd_fine_write_read* assembly_cmd_payload(int* cmdlen, const void* payload, size cmd_fine_write_read* assembly_cmd_payload(int* cmdlen, const void* payload, size_t payloadlen, const patcher_config* config, size_t readlen) { - size_t newlen = config->isSES?(config->nopad?sizeof(cmd_fine_write_read_SES_new):sizeof(cmd_fine_write_read_SES)):sizeof(cmd_fine_write_read_IAR); // 38+1, 44+1 + size_t newlen = config->isSES?(sizeof(cmd_fine_write_read) + config->endgap + 4*config->regCnt+4):sizeof(cmd_fine_write_read_IAR); // 38+1, 44+1 size_t payloadoffset = (uint32_t)&((cmd_fine_write_read*)0)->somelen; if (payloadoffset + payloadlen > newlen) { newlen = payloadoffset + payloadlen; // overlay @@ -77,24 +78,14 @@ cmd_fine_write_read* assembly_cmd_payload(int* cmdlen, const void* payload, size cmd->writelen = newlen - 1 - 0xC; // 2C/38/34 cmd->readlen = readlen; memcpy((char*)cmd + payloadoffset, payload, payloadlen); // 发送后40B0处是我们代码 + uint32_t endtolr = 0; if (config->isSES) { - if (config->nopad) { - cmd_fine_write_read_SES_new* ses = (cmd_fine_write_read_SES_new*)cmd; - ses->regLR = config->sp + 0x8 | 1; // BLX rxbuf时SP - ses->R4 = config->R4; - ses->R5 = config->R5; - ses->R6 = config->R6; - } else { - cmd_fine_write_read_SES* ses = (cmd_fine_write_read_SES*)cmd; - ses->regLR = config->sp + 0xC | 1; - ses->R4 = config->R4; - ses->R5 = config->R5; - ses->R6 = config->R6; - } + endtolr = 4 * config->regCnt + config->endgap; + memcpy((char*)(cmd + 1) + config->endgap, config->regs, 4 * config->regCnt); } else { - cmd_fine_write_read_IAR* iar = (cmd_fine_write_read_IAR*)cmd; - iar->regLR = config->sp + 0x10 | 1; // sp是BL rxbuf时候值. +4&readed,+8&arg,+10指向&somelen(payload入口点) + endtolr = 4; } + *(uint32_t*)((uint32_t)(cmd + 1) + endtolr) = config->sptop + 8 | 1; // sp是rxbuf时候(&arg), +8指向&somelen(payload入口点) return cmd; } @@ -105,10 +96,12 @@ enum payloadmode { pmM0Boot // m0patcher + uxbrx,m0boot }; - -#define CLOSE_AND_EXIT(code) UnloadWinusb();\ +#define CLOSE_AND_EXIT(code) shutdownKeeper();\ + UnloadWinusb();\ return code; +#define IMM32(x) uint8_t(x), uint8_t((x) >> 8), uint8_t((x) >> 16), (x) >> 24 + void printmismatch(const char* name, bool mismatch) { if (mismatch) { @@ -165,9 +158,9 @@ int main(int argc, char * argv[]) errprintf("Failed to find device!\n"); CLOSE_AND_EXIT(0); } else if (infovec.size() > 1) { - int i = 1; + size_t i = 1; for (JLinkInfoVec::const_iterator it = infovec.begin(); it != infovec.end(); it++, i++) { - printf("%d: %s [%d] sn %d%s\n", i, it->locationInfo.hubName.c_str(), it->locationInfo.devPort, it->winSerial, it->isWinusb?" WinUSB":""); + printf("%u: %s [%d] sn %d%s\n", i, it->locationInfo.hubName.c_str(), it->locationInfo.devPort, it->winSerial, it->isWinusb?" WinUSB":""); } printf("Input device index: "); scanf_s("%d", &i); @@ -188,11 +181,13 @@ int main(int argc, char * argv[]) dataBuffer[0x70] = 0; //isv9 = strstr((const char*)dataBuffer, "V9") != 0; isv10 = (strstr((const char*)dataBuffer, "V10") != 0) || (strstr((const char*)dataBuffer, "V11") != 0) || (strstr((const char*)dataBuffer, "V12") != 0); - if (is_BTL_version((char*)dataBuffer)) { + uint32_t hwversion; + LinkKeeper::commandGetHWVersion(&hwversion); + if (is_BTL_version((char*)dataBuffer) || hwversion == 0) { errprintf("Please quit Bootloader mode.\n"); CLOSE_AND_EXIT(0); } else { - printf("Firmware Version: %s\n", dataBuffer); + printf("Firmware Version: %s, Hardware Version: %d\n", dataBuffer, hwversion); } if (isv10 == false) { errprintf("Only support v10,v11,v12 devices.\n"); @@ -201,12 +196,13 @@ int main(int argc, char * argv[]) // check genuine hardware const patcher_config* config = find_patcher_config((char*)dataBuffer); uint32_t sn, snchecksum; - uint8_t snuidbuf[36]; + uint8_t snuidbuf[36]; // max 4+32 infact 4+16 void* otssign; bool sncheckerror = true; bool touchfeatures = _stricmp(payloadname, "revive") == 0; bool touchsn = _stricmp(payloadname, "setsn") == 0; bool touchcrp = _stricmp(payloadname, "swd") == 0; + bool touchbl = _stricmp(payloadname, "to10") == 0 || _stricmp(payloadname, "to11") == 0 || _stricmp(payloadname, "to12") == 0; if (LinkKeeper::commandReadOTSX(dataBuffer)) { sn = *(uint32_t*)dataBuffer; snchecksum = *(uint32_t*)(dataBuffer + 4); @@ -224,23 +220,25 @@ int main(int argc, char * argv[]) void* myapp = 0; int applen = 0; if (LinkKeeper::commandReadUID(&uidlen, &snuidbuf[4])) { - char* uidstr = base64_encode(&snuidbuf[4], uidlen); + uint8_t snuiddigest[20]; + sha1(snuidbuf, 4 + uidlen, snuiddigest); + char* hashstr = base64_encode(snuiddigest, sizeof(snuiddigest)); char* signstr = base64_encode((uint8_t*)otssign, 0x100); char* reply = 0; size_t replylen = 0; - int reqret = request_payload_online(sn, uidstr, signstr, payloadname, payloadopt, &reply, &replylen); + int reqret = request_payload_online(sn, hashstr, signstr, payloadname, payloadopt, &reply, &replylen); if (payloadopt) { free(payloadopt); } - if (uidstr) { - free(uidstr); + if (hashstr) { + free(hashstr); } if (signstr) { free(signstr); } if (reqret == 0 && replylen >= 8) { - int otsmatched = *(int32_t*)reply; - mode = *(int32_t*)(reply + 4); + int otsmatched = *(int32_t*)reply; // hash matches otssign? + mode = *(int32_t*)(reply + 4); // payload mode applen = replylen - 8; if (applen) { myapp = malloc(applen); @@ -262,43 +260,52 @@ int main(int argc, char * argv[]) errprintf("Reading UID failed!\n"); CLOSE_AND_EXIT(0); } - uint32_t dumpsize = config?0x8000:0x80000; - // dump bootloader/firmware and parse - char* fwdump = (char*)malloc(dumpsize); - if (LinkKeeper::dumpFullFirmware(0x1A000000, dumpsize, fwdump)) { - bool bootloaderok = is_offical_bootloader(fwdump); - if (touchcrp) { - printCRPlevel(*(uint32_t*)&fwdump[0x2FC]); - } - if (sn == -1 || sncheckerror || bootloaderok == false || otssignok == false) { - errprintf("Detected clone.\n"); + if (myapp == 0) { + errprintf("Payload \"%s\" was not found on server!\n", payloadname); + CLOSE_AND_EXIT(0); + } + // 如补丁bootloader需要获取bootloader检查能否经受补丁, 如没有找到config还需要获取firmware + if (touchbl || config == 0) { + // dump bootloader/firmware and parse + // TODO: bypass bootloader dump if not touchbl + //uint32_t dumpaddr = touchbl?0x1A000000:0x1A008000; + uint32_t dumpsize = config?0x8000:0x80000; + char* fwdump = (char*)malloc(dumpsize); + if (LinkKeeper::dumpFullFirmware(0x1A000000, dumpsize, fwdump)) { + bool bootloaderok = touchbl?is_offical_bootloader(fwdump):true; + if (touchcrp) { + printf("old CRP Level: "); + printCRPlevel(*(uint32_t*)&fwdump[0x2FC]); + } + if (sn == -1 || sncheckerror || bootloaderok == false || otssignok == false) { + errprintf("Detected clone.\n"); #ifdef DENYCLONE + free(fwdump); + if (myapp) { + free(myapp); + } + CLOSE_AND_EXIT(0); +#endif + } + } else { free(fwdump); + errprintf("Dumping failed. Can't check device's genuine.\n"); if (myapp) { free(myapp); } CLOSE_AND_EXIT(0); -#endif } - } else { + printf("Your version number is not present in config cache! Analyst it now...\n"); + config = analyst_firmware_stack(fwdump + 0x8000, 0x78000); free(fwdump); - errprintf("Dumping failed. Can't check device's genuine.\n"); - if (myapp) { - free(myapp); + } else if (touchcrp) { + uint32_t crp; + if (LinkKeeper::dumpFullFirmware(0x1A0002FC, 4, &crp)) { + printf("old CRP Level: "); + printCRPlevel(crp); } - CLOSE_AND_EXIT(0); - } - if (myapp == 0) { - errprintf("Payload \"%s\" was not found on server!\n", payloadname); - free(fwdump); - CLOSE_AND_EXIT(0); } - if (config == 0) { - printf("Your version number is not present in config cache! Analyst it now...\n"); - config = analyst_firmware_stack(fwdump + 0x8000, 0x78000); - } - free(fwdump); if (config == NULL) { free(myapp); CLOSE_AND_EXIT(0); @@ -306,7 +313,7 @@ int main(int argc, char * argv[]) uint32_t oldif; if (LinkKeeper::commandSendSelectInterface(3, &oldif)) { - printf("Change interface: %d -> 3\n", oldif); + printf("Select FINE interface: %d -> 3\n", oldif); } else { errprintf("Select interface failed!\n"); free(myapp); @@ -316,40 +323,32 @@ int main(int argc, char * argv[]) bool M0patched = false; int cmdlen; uint32_t readed; // FINE采样字节数, m0app设置 - // remotebuf 前4字节在设备会被填充readed, 因此不能放代码, 4+writebuf和remotebuf-4各可以放0x14大小代码 + // somelen(4)+writebuf(0x10) 可放14 + // replybuf 前4字节在设备会被填充readed, 因此不能放代码, 有效长度10, 在IAR版末尾送了4字节对齐, 有效长度14 // 此处代码要注意执行时候sp是100840E0(是LR末尾), 如有push会首先破坏LR位置,再继续往前破坏可能破坏自身 - // SES的代码局部变量readed会额外填充+28空隙, 导致第二段要拆分出来一个literal放入R4-R6区域 - if (mode == pmM4Ret && (config->isSES == false || (config->cmdReg >= 4 && config->cmdReg <= 6))) { + // SES的代码会入栈R4~R6, 布局改变导致Replybuf附赠4字节对齐没了. 如果使用2C的单次代码需要借用cmdreg做单独literal + if (mode == pmM4Ret) { // 单次溢出 cmd_fine_write_read* m4rxcmd; - if (config->isSES) { - // SES版+2C是R4位置, SES新版+28就是R4位置, 此代码有效长度2C(28+4) - unsigned char m4rxret[0x30] = { - 0x8C, 0xB0, 0x0A, 0x48, 0x4F, 0xF4, 0x00, 0x61, 0x05, 0x4A, 0x90, 0x47, 0x07, 0x48, 0x01, 0x30, - 0x80, 0x47, 0x01, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0xB0, 0xDF, 0xF8, 0x08, 0xF0, 0x00, 0x00, - 0xDB, 0x0E, 0x01, 0x1A, 0x19, 0x07, 0x01, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0x00, 0x00, 0x20 - }; - *(uint32_t*)&m4rxret[0x20] = config->usbrx | 1; - *(uint32_t*)&m4rxret[0x24] = config->lr | 1; // 要返回dispatchcmd - // 孤单literal的重定位 - m4rxret[0x2] += config->cmdReg - (config->nopad?5:4); - m4rxret[0xC] += config->cmdReg - (config->nopad?5:4); - m4rxcmd = assembly_cmd_payload(&cmdlen, m4rxret, sizeof(m4rxret)-8, config, 0); - if (config->nopad) { - *(&((cmd_fine_write_read_SES_new*)m4rxcmd)->R4 + config->cmdReg - 4) = *(uint32_t*)&m4rxret[0x2C]; // literal - } else { - *(&((cmd_fine_write_read_SES*)m4rxcmd)->R4 + config->cmdReg - 4) = *(uint32_t*)&m4rxret[0x2C]; // literal - } - } else { - unsigned char m4rxret[0x2C] = { - 0x8C, 0xB0, 0x07, 0x48, 0x4F, 0xF4, 0x00, 0x61, 0x06, 0x4A, 0x90, 0x47, 0x04, 0x48, 0x01, 0x30, - 0x80, 0x47, 0x01, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0xB0, 0xDF, 0xF8, 0x0C, 0xF0, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x20, 0xDB, 0x0E, 0x01, 0x1A, 0x19, 0x07, 0x01, 0x1A - }; - *(uint32_t*)&m4rxret[0x24] = config->usbrx | 1; - *(uint32_t*)&m4rxret[0x28] = config->lr | 1; // 要返回dispatchcmd - m4rxcmd = assembly_cmd_payload(&cmdlen, m4rxret, sizeof(m4rxret), config, 0); - } + // 此代码长度28, 内含4字节无用readed + unsigned char m4rxret[0x28] = { + 0x8C, 0xB0, // SUB SP, #0x30 + 0x05, 0x48, // LDR R0, =0x20000050 + 0x81, 0x0C, // LSRS R1, R0, #18 ; (2000>>2=800) + 0x06, 0x4A, // LDR R2, =0x1A010EDB + 0x90, 0x47, // BLX R2 ; usbrxbuf(rxdest,0x800) + 0x03, 0x48, // LDR R0, =0x20000050 ; myadpp = rxdest|1 + 0x01, 0x30, // ADDS R0, #1 + 0x80, 0x47, // BLX R0 ; myapp() + 0x0C, 0xB0, // ADD SP, #0x30 + 0x03, 0xE0, // B .+10 + IMM32(0x002eaded), // replybuf[readlen]=readed + IMM32(0x20000050), // rxdest + 0xDF, 0xF8, 0x04, 0xF0, // LDR.W PC, =0x1A010719 ; return to original LR + IMM32(config->usbrx|1), // usbrxbuf + IMM32(config->lr|1), // original LR in dispatchcmd/taskmain + }; + m4rxcmd = assembly_cmd_payload(&cmdlen, m4rxret, sizeof(m4rxret), config, 0); LinkKeeper::sendCommand(m4rxcmd, cmdlen, &readed, sizeof(readed)); free(m4rxcmd); } else { @@ -429,9 +428,9 @@ int main(int argc, char * argv[]) free(myapp); // 清理步骤, 如果打过M0补丁, 则恢复补丁, 重启版除外, 等他重启 if (M0patched && mode != pmM4Reset) { - uint32_t oldif2; - if (LinkKeeper::commandSendSelectInterface(oldif, &oldif2)) { - printf("Change interface: %d -> %d\n", oldif2, oldif); + uint32_t if3; + if (LinkKeeper::commandSendSelectInterface(oldif, &if3)) { + printf("Restore interface: %d -> %d\n", if3, oldif); } else { errprintf("Select interface failed!\n"); CLOSE_AND_EXIT(0); @@ -467,6 +466,7 @@ int main(int argc, char * argv[]) if (touchcrp) { uint32_t crp; if (LinkKeeper::dumpFullFirmware(0x1A0002FC, 4, &crp)) { + printf("new CRP Level: "); printCRPlevel(crp); } } @@ -542,6 +542,26 @@ bool sha256(char* buff, size_t buflen, void* digest) return ok; } +bool sha1(const void* buff, size_t buflen, void* digest) +{ + bool ok = false; + HCRYPTPROV provider; + HCRYPTHASH hash; + if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { + if (CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash)) { + if (CryptHashData(hash, (BYTE*)buff, buflen, 0)) { + DWORD digestlen = 20; + if (CryptGetHashParam(hash, HP_HASHVAL, (BYTE*)digest, &digestlen, 0)) { + ok = true; + } + } + } + } + CryptDestroyHash(hash); + CryptReleaseContext(provider, 0); + return ok; +} + bool aes_256_cbc_encrypt(const uint8_t* key, const uint8_t* iv, uint8_t* buff, size_t buflen) { bool ok = false; @@ -607,22 +627,35 @@ char* base64_encode(const uint8_t* value, size_t valuelen) bool is_offical_bootloader(const void* btl) { bool matched = false; - char* buff = (char*)malloc(0x54F8); - memcpy(buff, btl, 0x54F8); + bool pre2019 = (*(uint32_t*)btl + 1) == 0x1A0053E1; + const uint16_t blsize = pre2019?0x54F8:0x5D1C; + char* buff = (char*)malloc(blsize); + memcpy(buff, btl, blsize); *(uint32_t*)&buff[0x2FC] = 0x12345678; // CRP1 memset(&buff[0x130], 0xFF, 0x70); // Banner - buff[0x2F89] = '0'; // V10/V11 - if (*(uint16_t*)&buff[0x2EA0] != 0xB120) { + if (pre2019) { + buff[0x2F89] = '0'; // V10/V11 + } else { + buff[0x5CB1] = '2'; // V12 + } + if (pre2019 && *(uint16_t*)&buff[0x2EA0] != 0xB120) { printf("detected fake to12 Bootloader.\n"); - *(uint16_t*)&buff[0x2EA0] = 0xB120; // V12 CBZ patch + *(uint16_t*)&buff[0x2EA0] = 0xB120; // V10/V11 CBZ patch + } + if (!pre2019 && *(uint16_t*)&buff[0x469C] != 0xDB09) { + *(uint16_t*)&buff[0x469C] = 0xDB09; // V12 BLT patch } unsigned char digest[32]; - if (sha256(buff, 0x54F8, digest)) { + if (sha256(buff, blsize, digest)) { unsigned char myhash[32] = { 0x67, 0x90, 0xD1, 0xB9, 0x03, 0x2F, 0x1A, 0x89, 0x0D, 0xE0, 0xB4, 0x56, 0x56, 0x33, 0xE9, 0x79, 0xC7, 0x82, 0x71, 0x13, 0xB3, 0x28, 0x28, 0x6A, 0xD4, 0xE9, 0xC1, 0x70, 0xE5, 0x3E, 0xB7, 0x47 }; - matched = memcmp(digest, myhash, sizeof(myhash)) == 0; + unsigned char v12hash[32] = { + 0xBD, 0xFB, 0x89, 0x29, 0xA1, 0x08, 0xF4, 0x75, 0x9C, 0x70, 0x12, 0x3E, 0x24, 0x89, 0xBB, 0x6F, + 0xA4, 0x78, 0xC2, 0x62, 0x8D, 0x49, 0x6B, 0xDF, 0x8E, 0xE4, 0xB6, 0x2A, 0xB2, 0xED, 0xBA, 0xB8 + }; + matched = memcmp(digest, myhash, sizeof(myhash)) == 0 || memcmp(digest, v12hash, sizeof(v12hash)) == 0; } free(buff); return matched; diff --git a/EDUReViver/usbconn.cpp b/EDUReViver/usbconn.cpp index fbee1b3..1bb7d68 100644 --- a/EDUReViver/usbconn.cpp +++ b/EDUReViver/usbconn.cpp @@ -137,16 +137,28 @@ void JlinkDevice::open() CHAR rawio = TRUE; WinUsb_SetPipePolicy(winusbHandle, outep, RAW_IO, sizeof(rawio), &rawio); WinUsb_SetPipePolicy(winusbHandle, inep, RAW_IO, sizeof(rawio), &rawio); - //ULONG transize; - //ULONG transizelen = sizeof(transize); - //WinUsb_GetPipePolicy(winusbHandle, outep, MAXIMUM_TRANSFER_SIZE, &transizelen, &transize); - //transizelen = sizeof(transize); - //WinUsb_GetPipePolicy(winusbHandle, inep, MAXIMUM_TRANSFER_SIZE, &transizelen, &transize); - WINUSB_SETUP_PACKET setup = {0x41, 0x01, 0x0040, 0x0000, 0x0000}; + ULONG transizelen = sizeof(DWORD); + if (!WinUsb_GetPipePolicy(winusbHandle, outep, MAXIMUM_TRANSFER_SIZE, &transizelen, &this->writeSize)) { + this->writeSize = 2048; // default 2K, real 2M + } + ULONG readsize; + transizelen = sizeof(DWORD); + if (!WinUsb_GetPipePolicy(winusbHandle, inep, MAXIMUM_TRANSFER_SIZE, &transizelen, &readsize)) { + readsize = 2048; + } + if (readsize > 65536) { + readsize = 65536; + } + // 2K~8K =800~2000 + // 16K~64K=10~40 + USHORT value = (USHORT)(readsize>=16384?readsize/1024:readsize); + WINUSB_SETUP_PACKET setup = {0x41, 0x01, value, 0x0000, 0x0000}; ULONG transfered = 0; if (!WinUsb_ControlTransfer(winusbHandle, setup, NULL, 0, &transfered, NULL)) { printf("Fail to invoke WinUsb_ControlTransfer, last error %lu\n", GetLastError()); + readsize = 2048; } + this->readSize = readsize; DWORD timeout = 1000; WinUsb_SetPipePolicy(winusbHandle, outep, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout); WinUsb_SetPipePolicy(winusbHandle, inep, PIPE_TRANSFER_TIMEOUT, sizeof(timeout), &timeout); @@ -181,6 +193,8 @@ void JlinkDevice::open() CloseHandle(readPipeFile); return; } + DeviceIoControl(deviceFile, 0x220460, NULL, 0, &this->readSize, sizeof(DWORD), NULL, NULL); + DeviceIoControl(deviceFile, 0x220464, NULL, 0, &this->writeSize, sizeof(DWORD), NULL, NULL); this->deviceFile = deviceFile; this->readPipeFile = readPipeFile; @@ -191,15 +205,15 @@ void JlinkDevice::open() void JlinkDevice::close() { - if (deviceFile != INVALID_HANDLE_VALUE) { + HANDLE handle = (HANDLE)InterlockedExchange((LONG*)&deviceFile, (LONG)INVALID_HANDLE_VALUE); + if (handle != INVALID_HANDLE_VALUE) { if (isWinusb) { WinUsb_Free(interfaceHandle); } else { CloseHandle(readPipeFile); CloseHandle(writePipeFile); } - CloseHandle(deviceFile); - deviceFile = INVALID_HANDLE_VALUE; + CloseHandle(handle); g_recvpos = 0; } } @@ -573,6 +587,10 @@ JlinkDevice* LinkKeeper::getCurrDevice() bool LinkKeeper::processDeviceNotification(const char* devpath, const GUID* guid, bool add) { // 设备拔除时候, 已经无法正常解析ID等信息, 可适配的就是devpath + // main里面如果已经shutdownKeeper, 那么theKepper就是0了 + if (theKeeper == 0) { + return false; + } bool issegger2 = memcmp(guid, &seggerguid2, sizeof(seggerguid2)) == 0; bool iswinusb2 = memcmp(guid, &winusbguid2, sizeof(winusbguid2)) == 0; if (issegger2 || iswinusb2) { @@ -640,19 +658,17 @@ bool LinkKeeper::waitReconnect(uint32_t timeout, uint32_t step) return !theKeeper->fWaitReconnect; } -bool LinkKeeper::sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength) +bool LinkKeeper::sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultBufferLength) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { - return jlinkSendCommand(dev, commandBuffer, commandLength, resultBuffer, resultHeaderLength); + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkSendCommand(dev, commandBuffer, commandLength, resultBuffer, resultBufferLength); } return false; } bool LinkKeeper::continueReadResult(void* resultBuffer, uint32_t resultLength) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkContinueReadResult(dev, resultBuffer, resultLength); } return false; @@ -660,8 +676,7 @@ bool LinkKeeper::continueReadResult(void* resultBuffer, uint32_t resultLength) bool LinkKeeper::commandReadFirmwareVersion(void* dataBuffer) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkCommandReadFirmwareVersion(dev, dataBuffer); } return false; @@ -669,8 +684,7 @@ bool LinkKeeper::commandReadFirmwareVersion(void* dataBuffer) bool LinkKeeper::loopReadFirmwareVersion(void* dataBuffer) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkLoopReadFirmwareVersion(dev, dataBuffer); } return false; @@ -678,8 +692,7 @@ bool LinkKeeper::loopReadFirmwareVersion(void* dataBuffer) bool LinkKeeper::commandReadEmulatorMemory(uint32_t address, uint32_t length, void* dataBuffer) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkCommandReadEmulatorMemory(dev, address, length, dataBuffer); } return false; @@ -687,8 +700,7 @@ bool LinkKeeper::commandReadEmulatorMemory(uint32_t address, uint32_t length, vo bool LinkKeeper::commandSetEmulateOption(uint32_t option, uint32_t val, uint32_t* status) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkCommandSetEmulateOption(dev, option, val, status); } return false; @@ -696,8 +708,7 @@ bool LinkKeeper::commandSetEmulateOption(uint32_t option, uint32_t val, uint32_t bool LinkKeeper::commandSendUpdateFirmware(uint8_t* reply) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkCommandSendUpdateFirmware(dev, reply); } return false; @@ -705,8 +716,7 @@ bool LinkKeeper::commandSendUpdateFirmware(uint8_t* reply) bool LinkKeeper::commandSendSelectInterface(uint8_t newif, uint32_t* oldif) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkCommandSendSelectInterface(dev, newif, oldif); } return false; @@ -714,36 +724,49 @@ bool LinkKeeper::commandSendSelectInterface(uint8_t newif, uint32_t* oldif) bool LinkKeeper::dumpFullFirmware(uint32_t addr, uint32_t size, void* buf) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { return jlinkDumpFullFirmware(dev, addr, size, buf); } return false; } -bool LinkKeeper::commandReadUID(uint32_t* size, void* dataBuffer) +bool LinkKeeper::commandReadUID(uint32_t* size, void* uid) +{ + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkCommandReadUID(dev, size, uid); + } + return false; +} + +bool LinkKeeper::commandReadOTSX(void* otsx) +{ + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkCommandReadOTSX(dev, otsx); + } + return false; +} + +bool LinkKeeper::commandReadOTS(void* ots) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { - return jlinkCommandReadUID(dev, size, dataBuffer); + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkCommandReadOTS(dev, ots); } return false; } -bool LinkKeeper::commandReadOTSX(void* dataBuffer) +bool LinkKeeper::commandReadEmuCapsEx(void* capbits) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { - return jlinkCommandReadOTSX(dev, dataBuffer); + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkCommandReadEmuCapsEx(dev, capbits); } return false; + } -bool LinkKeeper::commandReadOTS(void* dataBuffer) +bool LinkKeeper::commandGetHWVersion(uint32_t* version) { - JlinkDevice* dev = theKeeper->getCurrDevice(); - if (dev) { - return jlinkCommandReadOTS(dev, dataBuffer); + if (JlinkDevice* dev = theKeeper->getCurrDevice()) { + return jlinkCommandGetHWVersion(dev, version); } return false; } @@ -837,7 +860,7 @@ bool lookupTopSeggerDevID(DEVINST* devinst, uint16_t vid, char* devid, char* hub USB_NODE_CONNECTION_DRIVERKEY_NAME* pnodename = (USB_NODE_CONNECTION_DRIVERKEY_NAME*)malloc(infosize); pnodename->ConnectionIndex = i + 1; if (DeviceIoControl(hubhandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, pnodename, infosize, pnodename, infosize, &readed, NULL)) { - if (wcsicmp(keyname, pnodename->DriverKeyName) == 0) { + if (_wcsicmp(keyname, pnodename->DriverKeyName) == 0) { *port = i + 1; free(pnodename); break; @@ -875,7 +898,7 @@ bool jlinkSendCommand(JlinkDevice* dev, void const* commandBuffer, uint32_t comm } else { ULONG readed = resultHeaderLength; while(g_recvpos < resultHeaderLength) { - if (WinUsb_ReadPipe(dev->interfaceHandle, dev->readPipe, (PUCHAR)&g_recvbuf[g_recvpos], 0x400, &readed, NULL)) { + if (WinUsb_ReadPipe(dev->interfaceHandle, dev->readPipe, (PUCHAR)&g_recvbuf[g_recvpos], sizeof(g_recvbuf) - g_recvpos, &readed, NULL)) { g_recvpos += readed; } } @@ -984,7 +1007,7 @@ bool jlinkDumpFullFirmware(JlinkDevice* dev, uint32_t addr, uint32_t size, void* { // is reset handler zero? bool usexor = false; - uint32_t handler; // 2017 03 10 以后的固件读出为0或者xor后结果 + uint32_t handler; // 2017 03 10 以后的固件读出为0或者dumper设置xor后结果 if (jlinkCommandReadEmulatorMemory(dev, addr + 4, 4, &handler) && (((handler >> 24) != (addr >> 24)) || handler == 0)) { usexor = true; uint32_t status = -1; @@ -994,10 +1017,10 @@ bool jlinkDumpFullFirmware(JlinkDevice* dev, uint32_t addr, uint32_t size, void* } } } - - for (uint32_t pos = 0; pos < size; pos += 0x200, addr += 0x200) { + // 0x200 crash in 2023 + for (uint32_t pos = 0; pos < size; pos += 0x100, addr += 0x100) { for (int i = 0; i < 20; i++) { - size_t lesssize = min(0x200, size); + size_t lesssize = min(0x100, size); if (jlinkCommandReadEmulatorMemory(dev, addr, lesssize, (char*)buf + pos)) { if (usexor) { uint32_t xorkey = 0x55; @@ -1044,25 +1067,39 @@ bool jlinkCommandReadUID(JlinkDevice* dev, uint32_t* size, void* dataBuffer) return jlinkContinueReadResult(dev, dataBuffer, leftLength); } -bool jlinkCommandReadOTSX(JlinkDevice* dev, void* dataBuffer) +bool jlinkCommandReadOTSX(JlinkDevice* dev, void* otsx) { uint8_t commandBuffer[14] = { 0x16, 0x02 }; - *(uint32_t*)&commandBuffer[2] = 0; + *(uint32_t*)&commandBuffer[2] = 0; // fixed replylength 0x200 memcpy(&commandBuffer[6], "IDSEGGER", 8); uint32_t leftLength = 0; if (!jlinkSendCommand(dev, commandBuffer, sizeof(commandBuffer), &leftLength, sizeof(leftLength))) return false; - return jlinkContinueReadResult(dev, dataBuffer, leftLength); + return jlinkContinueReadResult(dev, otsx, leftLength); } -bool jlinkCommandReadOTS(JlinkDevice* dev, void* dataBuffer) +bool jlinkCommandReadOTS(JlinkDevice* dev, void* ots) { uint8_t command = 0xE6; - return jlinkSendCommand(dev, &command, sizeof(command), dataBuffer, 0x100); + return jlinkSendCommand(dev, &command, sizeof(command), ots, 0x100); +} + +bool jlinkCommandReadEmuCapsEx(JlinkDevice* dev, void* capbits) +{ + uint8_t command = 0xED; + + return jlinkSendCommand(dev, &command, sizeof(command), capbits, 0x20); +} + +bool jlinkCommandGetHWVersion(JlinkDevice* dev, uint32_t* version) +{ + uint8_t command = 0xF0; + + return jlinkSendCommand(dev, &command, sizeof(command), version, sizeof(*version)); } diff --git a/EDUReViver/usbconn.h b/EDUReViver/usbconn.h index 78e173c..81823ec 100644 --- a/EDUReViver/usbconn.h +++ b/EDUReViver/usbconn.h @@ -55,6 +55,8 @@ struct JlinkDevice : JlinkDeviceInfo { UCHAR writePipe; // 81 }; }; + DWORD readSize; + DWORD writeSize; void open(); void close(); }; @@ -88,7 +90,7 @@ class LinkKeeper { static bool selectDevice(const hublocation& location); static void prepareReconnect(); static bool waitReconnect(uint32_t timeout, uint32_t step); - static bool sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultHeaderLength); + static bool sendCommand(void const* commandBuffer, uint32_t commandLength, void* resultBuffer, uint32_t resultBufferLength); static bool continueReadResult(void* resultBuffer, uint32_t resultLength); static bool commandReadFirmwareVersion(void* dataBuffer); static bool loopReadFirmwareVersion(void* dataBuffer); @@ -97,9 +99,11 @@ class LinkKeeper { static bool commandSendUpdateFirmware(uint8_t* reply); static bool commandSendSelectInterface(uint8_t newif, uint32_t* oldif); static bool dumpFullFirmware(uint32_t addr, uint32_t size, void* buf); - static bool commandReadUID(uint32_t* size, void* dataBuffer); - static bool commandReadOTSX(void* dataBuffer); - static bool commandReadOTS(void* dataBuffer); + static bool commandReadUID(uint32_t* size, void* uid); + static bool commandReadOTSX(void* otsx); + static bool commandReadOTS(void* ots); + static bool commandReadEmuCapsEx(void* capbits); + static bool commandGetHWVersion(uint32_t* version); }; extern LinkKeeper* theKeeper; @@ -132,7 +136,9 @@ bool jlinkCommandSendUpdateFirmware(JlinkDevice* dev, uint8_t* reply); bool jlinkCommandSendSelectInterface(JlinkDevice* dev, uint8_t newif, uint32_t* oldif); bool jlinkDumpFullFirmware(JlinkDevice* dev, uint32_t addr, uint32_t size, void* buf); bool jlinkCommandReadUID(JlinkDevice* dev, uint32_t* size, void* dataBuffer); -bool jlinkCommandReadOTSX(JlinkDevice* dev, void* dataBuffer); // cmd16 otsx, size 0x200 -bool jlinkCommandReadOTS(JlinkDevice* dev, void* dataBuffer); // cmde6 size 0x100 +bool jlinkCommandReadOTSX(JlinkDevice* dev, void* otsx); // cmd16 otsx, size 0x200 +bool jlinkCommandReadOTS(JlinkDevice* dev, void* ots); // cmde6 size 0x100 +bool jlinkCommandReadEmuCapsEx(JlinkDevice* dev, void* capbits); // 53 of 256bits used +bool jlinkCommandGetHWVersion(JlinkDevice* dev, uint32_t* version); #endif \ No newline at end of file diff --git a/README.md b/README.md index c416e50..95b374d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ J-Link EDU Reviver 使用方法 -------- -从右侧[releases](https://github.com/banxian/EDUReviver/releases)页面下载最新[可执行文件包](https://github.com/banxian/EDUReviver/releases/download/v0.3.6-beta/EDUReviver_bin_b036.zip). +从右侧[releases](https://github.com/banxian/EDUReviver/releases)页面下载最新[可执行文件包](https://github.com/banxian/EDUReviver/releases/download/v0.3.7-beta/EDUReviver_bin_b037.zip). 解压所有文件到目录中, 进入目录在命令行下执行想要的命令 EDUReViver -run blinky @@ -13,10 +13,10 @@ EDUReViver -run revive 去除多余的FlashDL之类的Features. EDUReViver -run swd -打开电路板SWD调试接口. +打开JLink电路板调试接口, 可以用来救砖. EDUReViver -run swd off -关闭电路板SWD调试接口. +关闭JLink电路板调试接口. EDUReViver -run to11 转换V10/V12到V11. 重新插拔后, 打开jlink commander会自动刷新固件. @@ -55,10 +55,10 @@ EDUReViver -run revive this payload remove all extra features. EDUReViver -run swd -this payload unlocking SWD debug port on PCB. +this payload unlocking SWD debugging on JLink PCB. EDUReViver -run swd off -this payload locking SWD debug port on PCB again. +this payload locking SWD debugging on JLink PCB again. EDUReViver -run to11 this payload turns your V10/fakeV12 to V11. unplug and replug usb cable, then flash new firmware in jlink commander.