Skip to content

Failed to parse JSON from jsdec #3345

@vtu-dog

Description

@vtu-dog

Environment information

  • Operating System: macOS Sonoma 14.4.1 (23E224)
  • Cutter version: 2.3.4-stable-209c26b
  • Obtained from:
    • Built from source
    • Downloaded release from Cutter website or GitHub
    • Distribution repository (brew)
  • File format: mach0

Describe the bug

  1. I wanted to disassemble a hello world program written in C to get a feel of Cutter's workflow. Unfortunately, jsdec died as soon as I pointed it to a main function. The Ghidra decompiler worked fine.

The code in question, compiled with $ gcc main.c:

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
}

Error log:

[0x100003f6c]> pddi
{"name":"issue_1716306668046","arch":"arm","archbits":64,"graph":[{"name":"entry0","blocks":[{"address":4294983532,"ops":[{"offset":4294983532,"opcode":"stp fp, lr, [sp, -0x10]!","disasm":"stp fp, lr, [var_10h]!","type":"store","comment":"[00] -r-x section size 32 named 0.__TEXT.__text"},{"offset":4294983536,"val":0,"opcode":"mov fp, sp","disasm":"mov fp, sp","type":"add"},{"offset":4294983540,"ptr":4294979584,"opcode":"adrp x0, 0x100003000","disasm":"adrp x0, data.100003000","type":"lea"},{"offset":4294983544,"val":3992,"opcode":"add x0, x0, 0xf98","disasm":"add x0, x0, 0xf98","type":"add"},{"offset":4294983548,"opcode":"bl 0x100003f8c","disasm":"bl printf","type":"call","jump":4294983564,"fail":4294983552},{"offset":4294983552,"ptr":0,"val":0,"opcode":"mov w0, 0","disasm":"mov w0, 0","type":"mov"},{"offset":4294983556,"ptr":0,"opcode":"ldp fp, lr, [sp], 0x10","disasm":"ldp fp, lr, [sp], 0x10","type":"load"},{"offset":4294983560,"opcode":"ret","disasm":"ret","type":"ret"}]}]}],"isj":[{"name":"__mh_execute_header","flagname":"sym.__mh_execute_header","realname":"__mh_execute_header","ordinal":0,"bind":"GLOBAL","size":0,"type":"FUNC","vaddr":4294967296,"paddr":0,"is_imported":false,"lib":""},{"name":"_main","flagname":"sym._main","realname":"_main","ordinal":1,"bind":"GLOBAL","size":0,"type":"FUNC","vaddr":4294983532,"paddr":16236,"is_imported":false,"lib":""},{"name":"imp.printf","flagname":"sym.imp.printf","realname":"printf","ordinal":2,"bind":"LOCAL","size":0,"type":"FUNC","vaddr":4294983564,"paddr":16268,"is_imported":true,"lib":""},{"name":"func.100003f6c","flagname":"sym.func.100003f6c","realname":"func.100003f6c","ordinal":3,"bind":"LOCAL","size":0,"type":"FUNC","vaddr":4294983532,"paddr":16236,"is_imported":false,"lib":""}],"Csj":[{"offset":4294983576,"type":"Cs","name":"SGVsbG8sIFdvcmw=","enc":"ascii","ascii":true}],"icj":[],"afvj":Usage: a  [abdefFghoprxstc] [...]| a*                 same as afl*;ah*;ax*| aa[?]              analyze all (fcns + bbs) (aa0 to avoid sub renaming)| a8 [hexpairs]      analyze bytes| ab[?] [addr]       analyze block| ad[?]              analyze data trampoline (wip)| ad [from] [to]     analyze data pointers to (from-to)| ae[?] [expr]       analyze opcode eval expression (see ao)| af[?]              analyze Functions| aF                 same as above, but using analysis.depth=1| ag[?] [options]    draw graphs in various formats| ah[?]              analysis hints (force opcode size, ...)| ai [addr]          address information (show perms, stack, heap, ...)| aj                 same as a* but in json (aflj)| aL                 list all asm/analysis plugins (e asm.arch=?)| an [name] [@addr]  show/rename/create whatever flag/function is used at addr| ao[?] [len]        analyze Opcodes (or emulate it)| aO[?] [len]        Analyze N instructions in M bytes| ap                 find prelude for current offset| ar[?]              like 'dr' but for the esil vm. (registers)| as[?] [num]        analyze syscall using dbg.reg| av[?] [.]          show vtables| ax[?]              manage refs/xrefs (see also afx?),"afcfj":[{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]},{"name":"entry0","noreturn":false,"ret":"void","cc":"arm64","args":[]}],"aflj":[{"offset":4294983532,"name":"entry0","size":32,"is-pure":false,"realsz":32,"noreturn":false,"stackframe":16,"calltype":"arm64","cost":2,"cc":1,"loops":0,"bits":64,"type":"fcn","nbbs":1,"edges":0,"ebbs":1,"signature":"entry0();","minbound":4294983532,"maxbound":4294983564,"callrefs":[{"from":4294983548,"to":4294983564,"type":"CALL"}],"datarefs":[{"from":4294983536,"to":1540080,"type":"DATA"},{"from":4294983540,"to":4294979584,"type":"DATA"},{"from":4294983544,"to":4294983576,"type":"DATA"},{"from":4294983556,"to":1540080,"type":"DATA"},{"from":4294983556,"to":1540088,"type":"DATA"}],"codexrefs":[],"dataxrefs":[],"indegree":0,"outdegree":1,"nlocals":2,"nargs":0,"stackvars":[{"name":"var_10h","arg":false,"type":"int64_t","storage":{"type":"stack","stack":-16}},{"name":"var_8h","arg":false,"type":"int64_t","storage":{"type":"stack","stack":-8}}],"regvars":[]},{"offset":4294983564,"name":"sym.imp.printf","size":12,"is-pure":false,"realsz":12,"noreturn":false,"stackframe":0,"calltype":"arm64","cost":0,"cc":1,"loops":0,"bits":64,"type":"sym","nbbs":1,"edges":0,"ebbs":1,"signature":"int sym.imp.printf(const char *format);","minbound":4294983564,"maxbound":4294983576,"callrefs":[{"from":4294983572,"to":4295016456,"type":"CODE"}],"datarefs":[{"from":4294983564,"to":4294983680,"type":"STRING"},{"from":4294983568,"to":4294983680,"type":"DATA"},{"from":4294983568,"to":4295016456,"type":"DATA"}],"codexrefs":[{"from":4294983548,"to":4294983564,"type":"CALL"}],"dataxrefs":[],"indegree":1,"outdegree":0,"nlocals":0,"nargs":0,"stackvars":[],"regvars":[]}]} 
  1. To add insult to the injury, the main function was not detected automatically, and I had to resort to manually selecting the offset from the entry0 blob. It might be related to the first issue, but I honestly have no idea.

To Reproduce

Steps to reproduce the behavior:

  1. Compile the above code using gcc (so clang in a trenchcoat, since I'm on macOS).
  2. Load a.out into Cutter, analysis level: auto.
  3. Select the right offset.

Expected behavior

  1. The disassembler should not crash.
  2. The main function should be visible in the sidebar.

Screenshots

screenshot

Additional context

I did not raise the issue in the jsdec repository, because it seems to be a problem with Cutter calling it incorrectly.

In case you'd like to inspect the binary yourself, I can send it in a .zip file here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions