Fix x64 and x86 SEH analysis (#6558)

This commit is contained in:
Naren Sirigere 2026-07-04 13:16:13 +05:30 committed by GitHub
parent 84b2f31035
commit 3c02fa5618
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 339 additions and 37 deletions

View file

@ -583,6 +583,49 @@ static bool is_unknown_call_from_plt(RzAnalysis *analysis, ut64 op_address) {
RZ_STR_EQ(s->name, ".plt");
}
typedef struct rz_analysis_trycatch_ctx_t {
RzAnalysis *analysis;
RzVector /*<RzAnalysisTaskItem>*/ *tasks;
RzAnalysisFunction *fcn;
RzStackAddr sp;
ut64 addr;
bool overlapped;
RzAnalysisBlock *bb;
} RzAnalysisTrycatchCtx;
static bool add_trycatch_handlers(RZ_NONNULL RzAnalysisTrycatchCtx *ctx) {
if (!ctx->analysis->binb.get_trycatch || !ctx->analysis->binb.bin) {
return false;
}
RzPVector *tcs = ctx->analysis->binb.get_trycatch(ctx->analysis->binb.bin);
if (!tcs) {
return false;
}
bool found = false;
void **it;
RzBinTrycatch *tc;
rz_pvector_foreach (tcs, it) {
tc = *it;
if (ctx->addr >= tc->from && ctx->addr < tc->to && tc->handler) {
if (!ctx->overlapped && !found && ctx->bb) {
ctx->bb->jump = tc->handler;
}
rz_analysis_task_item_new(ctx->analysis, ctx->tasks, ctx->fcn, NULL, tc->handler, ctx->sp);
found = true;
}
}
return found;
}
static inline bool is_x86_seh(RzAnalysis *analysis, bool is_x86, RzAnalysisOp *op, ut64 last_push_addr) {
return analysis->opt.trycatch && is_x86 && op->dst && op->dst->seg &&
RZ_STR_EQ(op->dst->seg->name, "fs") && op->dst->delta == 0 &&
op->dst->memref && last_push_addr != UT64_MAX &&
analysis->iob.is_valid_offset(analysis->iob.io, last_push_addr, 0);
}
/**
* \brief Analyses the given task item \p item for branches.
*
@ -843,34 +886,21 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
rz_analysis_block_set_size(bb, newbbsize);
fcn->ninstr++;
}
if (analysis->opt.trycatch) {
const char *name = analysis->coreb.getName(analysis->coreb.core, at);
if (name) {
if (rz_str_startswith(name, "try.") && rz_str_endswith(name, ".from")) {
char *handle = rz_str_dup(name);
// handle = rz_str_replace (handle, ".from", ".to", 0);
ut64 from_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
handle = rz_str_replace(handle, ".from", ".catch", 0);
ut64 handle_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
handle = rz_str_replace(handle, ".catch", ".filter", 0);
ut64 filter_addr = analysis->coreb.numGet(analysis->coreb.core, handle);
if (filter_addr) {
rz_analysis_xrefs_set(analysis, op.addr, filter_addr, RZ_ANALYSIS_XREF_TYPE_CALL);
if (analysis->opt.trycatch && analysis->binb.get_trycatch) {
RzPVector *tcs = analysis->binb.get_trycatch(analysis->binb.bin);
if (tcs) {
void **it;
RzBinTrycatch *tc;
rz_pvector_foreach (tcs, it) {
tc = *it;
if (tc->from != at) {
continue;
}
bb->jump = at + oplen;
if (from_addr != bb->addr) {
bb->fail = handle_addr;
ret = analyze_function_locally(analysis, fcn, handle_addr);
if (bb->size == 0) {
rz_analysis_function_remove_block(fcn, bb);
}
rz_analysis_block_update_hash(bb);
rz_analysis_block_unref(bb);
bb = fcn_append_basic_block(analysis, fcn, bb->jump);
if (!bb) {
gotoBeach(RZ_ANALYSIS_RET_ERROR);
}
if (tc->filter) {
rz_analysis_xrefs_set(analysis, op.addr, tc->filter, RZ_ANALYSIS_XREF_TYPE_CALL);
}
rz_analysis_xrefs_set(analysis, op.addr, tc->handler, RZ_ANALYSIS_XREF_TYPE_CODE);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, tc->handler, sp);
}
}
}
@ -992,6 +1022,11 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
gotoBeach(RZ_ANALYSIS_RET_END);
}
}
if (is_x86_seh(analysis, is_x86, &op, last_push_addr)) {
rz_analysis_xrefs_set(analysis, op.addr, last_push_addr, RZ_ANALYSIS_XREF_TYPE_CODE);
rz_analysis_task_item_new(analysis, tasks, fcn, NULL, last_push_addr, sp);
last_push_addr = UT64_MAX;
}
break;
case RZ_ANALYSIS_OP_TYPE_LEA:
last_is_reg_mov_lea = false;
@ -1121,6 +1156,12 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
}
gotoBeach(RZ_ANALYSIS_RET_BRANCH);
}
if (analysis->opt.trycatch) {
RzAnalysisTrycatchCtx ctx = { analysis, tasks, fcn, sp, at, overlapped, bb };
if (add_trycatch_handlers(&ctx)) {
gotoBeach(RZ_ANALYSIS_RET_BRANCH);
}
}
gotoBeach(RZ_ANALYSIS_RET_END);
}
{
@ -1273,6 +1314,7 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
case RZ_ANALYSIS_OP_TYPE_RCALL:
case RZ_ANALYSIS_OP_TYPE_ICALL:
case RZ_ANALYSIS_OP_TYPE_IRCALL:
last_push_addr = UT64_MAX;
/* call [dst] */
// XXX: this is TYPE_MCALL or indirect-call
(void)rz_analysis_xrefs_set(analysis, op.addr, op.ptr, RZ_ANALYSIS_XREF_TYPE_CALL);
@ -1283,11 +1325,18 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
if (f) {
f->is_noreturn = true;
}
if (analysis->opt.trycatch) {
RzAnalysisTrycatchCtx ctx = { analysis, tasks, fcn, sp, at, overlapped, bb };
if (add_trycatch_handlers(&ctx)) {
gotoBeach(RZ_ANALYSIS_RET_BRANCH);
}
}
gotoBeach(RZ_ANALYSIS_RET_END);
}
break;
case RZ_ANALYSIS_OP_TYPE_CCALL:
case RZ_ANALYSIS_OP_TYPE_CALL:
last_push_addr = UT64_MAX;
/* call dst */
(void)rz_analysis_xrefs_set(analysis, op.addr, op.jump, RZ_ANALYSIS_XREF_TYPE_CALL);
@ -1296,6 +1345,12 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
if (f) {
f->is_noreturn = true;
}
if (analysis->opt.trycatch) {
RzAnalysisTrycatchCtx ctx = { analysis, tasks, fcn, sp, at, overlapped, bb };
if (add_trycatch_handlers(&ctx)) {
gotoBeach(RZ_ANALYSIS_RET_BRANCH);
}
}
gotoBeach(RZ_ANALYSIS_RET_END);
}

View file

@ -583,12 +583,26 @@ RZ_API void rz_bin_class_free(RZ_NULLABLE RzBinClass *k) {
free(k);
}
RZ_API RZ_OWN RzPVector /*<RzBinTrycatch *>*/ *rz_bin_file_get_trycatch(RZ_NONNULL RzBinFile *bf) {
rz_return_val_if_fail(bf && bf->o && bf->o->plugin, NULL);
if (bf->o->plugin->trycatch) {
return bf->o->plugin->trycatch(bf);
/**
* \brief Get the trycatch information from the given binary file.
*
* If the trycatch information has not been parsed yet, it will call the plugin's
* trycatch method to load it, if that fails then an empty vector will be returned.
*
* \param bf Binary file
* \return Borrowed vector of RzBinTrycatch pointers
*/
RZ_API RZ_BORROW RzPVector /*<RzBinTrycatch *>*/ *rz_bin_file_get_trycatch(RZ_NONNULL RzBinFile *bf) {
rz_return_val_if_fail(bf && bf->o, NULL);
if (!bf->o->trycatch) {
if (bf->o->plugin && bf->o->plugin->trycatch) {
bf->o->trycatch = bf->o->plugin->trycatch(bf);
}
if (!bf->o->trycatch) {
bf->o->trycatch = rz_pvector_new((RzPVectorFree)rz_bin_trycatch_free);
}
}
return NULL;
return bf->o->trycatch;
}
RZ_API RzPVector /*<RzBinSymbol *>*/ *rz_bin_file_get_symbols(RzBinFile *bf) {

View file

@ -978,6 +978,12 @@ static RzBinObject *bin_bind_get_bin_object(RzBin *bin) {
return bf ? bf->o : NULL;
}
static RzPVector /*<RzBinTrycatch *>*/ *bin_bind_get_trycatch(RzBin *bin) {
rz_return_val_if_fail(bin, NULL);
RzBinFile *bf = rz_bin_cur(bin);
return bf ? rz_bin_file_get_trycatch(bf) : NULL;
}
RZ_API void rz_bin_bind(RzBin *bin, RzBinBind *b) {
if (!b) {
return;
@ -990,6 +996,7 @@ RZ_API void rz_bin_bind(RzBin *bin, RzBinBind *b) {
b->get_vsect_at = bin_bind_get_vsection_at;
b->demangle = rz_bin_demangle;
b->get_bin_object = bin_bind_get_bin_object;
b->get_trycatch = bin_bind_get_trycatch;
}
RZ_API RzBuffer *rz_bin_create(RzBin *bin, const char *p,

View file

@ -207,6 +207,7 @@ RZ_IPI void rz_bin_object_free(RzBinObject *o) {
rz_pvector_free(o->mem);
rz_pvector_free(o->sections);
rz_pvector_free(o->symbols);
rz_pvector_free(o->trycatch);
rz_pvector_free(o->vfiles);
rz_pvector_free(o->resources);
for (ut32 i = 0; i < RZ_BIN_SPECIAL_SYMBOL_LAST; i++) {

View file

@ -5654,8 +5654,6 @@ RZ_API bool rz_core_bin_trycatch_print(RZ_NONNULL RzCore *core, RZ_NONNULL RzBin
}
}
rz_pvector_free(trycatch);
rz_cmd_state_output_array_end(state);
return true;
}

View file

@ -3057,7 +3057,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETCB("analysis.jmp.mid", "true", &cb_analysis_jmpmid, "Continue analysis after jump to middle of instruction (x86 only)");
SETCB("analysis.refstr", "false", &cb_analysis_searchstringrefs, "Search string references in data references");
SETCB("analysis.trycatch", "false", &cb_analysis_trycatch, "Honor try.X.Y.{from,to,catch} flags");
SETCB("analysis.trycatch", "true", &cb_analysis_trycatch, "Honor try.X.Y.{from,to,catch} flags");
SETCB("analysis.bb.maxsize", "63K", &cb_analysis_bb_max_size, "Maximum basic block size");
SETCB("analysis.fcn_max_size", "256K", &cb_analysis_fcn_max_size, "Maximum function size (unspecified units)");
SETCB("analysis.pushret", "false", &cb_analysis_pushret, "Analyze push+ret as jmp");

View file

@ -338,6 +338,7 @@ typedef struct rz_bin_object_t {
RzPVector /*<RzBinSection *>*/ *sections;
RzPVector /*<RzBinImport *>*/ *imports;
RzPVector /*<RzBinSymbol *>*/ *symbols;
RzPVector /*<RzBinTrycatch *>*/ *trycatch;
RzPVector /*<RzBinResource *>*/ *resources;
/**
* \brief Acceleration structure for fast access of the symbol for a given import.
@ -881,6 +882,7 @@ typedef const RzPVector *(*RzBinGetSections)(RzBinObject *obj);
typedef RzBinSection *(*RzBinGetSectionAt)(RzBin *bin, ut64 addr);
typedef char *(*RzBinDemangle)(RzBin *bin, const char *language, const char *mangled);
typedef RzBinObject *(*RzBinGetObject)(RzBin *bin);
typedef RzPVector /*<RzBinTrycatch *>*/ *(*RzBinGetTrycatch)(RzBin *bin);
typedef struct rz_bin_bind_t {
RzBin *bin;
@ -890,6 +892,7 @@ typedef struct rz_bin_bind_t {
RzBinGetSectionAt get_vsect_at;
RzBinDemangle demangle;
RzBinGetObject get_bin_object;
RzBinGetTrycatch get_trycatch;
ut32 visibility;
} RzBinBind;
@ -1020,7 +1023,7 @@ RZ_API RZ_OWN RzPVector /*<RzBinString *>*/ *rz_bin_file_strings(RZ_NONNULL RzBi
// use RzBinFile instead
RZ_DEPRECATE RZ_API int rz_bin_is_static(RZ_NONNULL RzBin *bin);
RZ_API RZ_OWN RzPVector /*<RzBinTrycatch *>*/ *rz_bin_file_get_trycatch(RZ_NONNULL RzBinFile *bf);
RZ_API RZ_BORROW RzPVector /*<RzBinTrycatch *>*/ *rz_bin_file_get_trycatch(RZ_NONNULL RzBinFile *bf);
RZ_API RZ_BORROW const RzPVector /*<RzBinAddr *>*/ *rz_bin_object_get_entries(RZ_NONNULL RzBinObject *obj);
RZ_API const RzPVector /*<RzBinField *>*/ *rz_bin_object_get_fields(RZ_NONNULL RzBinObject *obj);

View file

@ -44,7 +44,7 @@ EXPECT=<<EOF
arch x86
machine AMD 64
0 * classes
86 * functions
87 * functions
38 * imports
0 * platform.ports
80 * pointers

View file

@ -43,6 +43,7 @@ afl.
EOF
EXPECT=<<EOF
0x00401e80 fcn.00401e80
0x00401e80 fcn.00401e80
EOF
RUN
@ -530,7 +531,7 @@ s 0x401880
fd
EOF
EXPECT=<<EOF
fcn.00401880
fcn.00401820 + 96
EOF
RUN
@ -4261,3 +4262,137 @@ EXPECT=<<EOF
\ |,=< 0x00401054 jmp fcn.0040dfd0
EOF
RUN
NAME=x86 structured exception handling xframe
FILE=bins/pe/microsoft_seh_tests/x86/xframe_eh_exe.exe
CMDS=<<EOF
aaa
pdf @ main
EOF
EXPECT=<<EOF
; CALL XREF from entry0 @ 0x401d37
/ int main(int argc, char **argv, char **envp);
| 0x00401b10 call fcn.00401880
| 0x00401b15 call fcn.00401000
| 0x00401b1a call fcn.00401320
| 0x00401b1f push str.Caught_Exceptions_Test_PASSED. ; 0x4031b0 ; "Caught Exceptions Test PASSED." ; const char *s
| 0x00401b24 call dword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; 0x4030cc ; int puts(const char *s)
| 0x00401b2a call fcn.004019a0
| 0x00401b2f push str.Resumed_Exceptions_Test_PASSED. ; 0x4031d0 ; "Resumed Exceptions Test PASSED." ; const char *s
| 0x00401b34 call dword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; 0x4030cc ; int puts(const char *s)
| 0x00401b3a add esp, 0x08
| 0x00401b3d xor eax, eax
\ 0x00401b3f ret
EOF
RUN
NAME=x86 structured exception handling nested_collided
FILE=bins/pe/microsoft_seh_tests/x86/nested_collided.exe
CMDS=<<EOF
aaa
pdr @ main
EOF
EXPECT=<<EOF
; CALL XREF from entry0 @ 0x40160e
/ int main(int argc, char **argv, char **envp);
| ; var int32_t var_3ch @ stack - 0x3c
| ; var int32_t var_30h @ stack - 0x30
| ; var int32_t var_2ch @ stack - 0x2c
| ; var int32_t var_1ch @ stack - 0x1c
| ; var int32_t var_14h @ stack - 0x14
| ; var int32_t var_ch @ stack - 0xc
| 0x00401280 push ebp
| 0x00401281 mov ebp, esp
| 0x00401283 push 0xfffffffe ; 0xfe ; 254 ; int32_t var_20h
| 0x00401285 push data.00403618 ; 0x403618 ; ub"\U0000feff\xff\xff" ; int32_t var_1ch
| 0x0040128a push fcn.00401417 ; 0x401417 ; "U\x8b\xecV\x8bu\b\xff6\xe8\xf8\v" ; int32_t var_28h
| 0x0040128f mov eax, dword fs:[0x0]
| 0x00401295 push eax
| 0x00401296 sub esp, 0x08
| 0x00401299 push ebx
| 0x0040129a push esi
| 0x0040129b push edi
| 0x0040129c mov eax, dword [data.00404004] ; [0x404004:4]=0xbb40e64e ; "N\xe6@\xbb\xff\xff\xff\xff\U00000001"
| 0x004012a1 xor dword [var_ch], eax
| 0x004012a4 xor eax, ebp
| 0x004012a6 push eax ; int32_t arg_4h
| 0x004012a7 lea eax, dword [var_14h]
| 0x004012aa mov dword fs:[0x0], eax
| 0x004012b0 mov dword [var_1ch], esp
| 0x004012b3 push str.Collided_Unwind_test... ; 0x403108 ; "Collided Unwind test... " ; int32_t arg_8h
| 0x004012b8 call fcn.00401030
| 0x004012bd add esp, 0x04
| 0x004012c0 cmp byte [data.00404374], 0x00 ; [0x404374:1]=0
| 0x004012c7 jz 0x4012ca
| ----------- true: 0x004012ca false: 0x004012c9
| 0x004012c9 int3
| 0x004012ca mov dword [data.00404388], 0x01 ; [0x404388:4]=0
| 0x004012d4 mov dword [data.0040438c], 0x00 ; [0x40438c:4]=0
| 0x004012de mov dword [var_30h], 0x00
| 0x004012e5 call fcn.004011e0
| 0x004012ea jmp 0x401323
| ----------- true: 0x00401323
| ; CODE XREF from main @ 0x4012ea
| 0x00401323 mov dword [var_30h], 0xfffffffe ; 4294967294
| 0x0040132a cmp byte [data.00404374], 0x00 ; [0x404374:1]=0
| 0x00401331 jz 0x401334
| ----------- true: 0x00401334 false: 0x00401333
| 0x00401333 int3
| 0x00401334 cmp dword [data.00404388], 0x40bf ; [0x404388:4]=0
| 0x0040133e jnz 0x401349
| ----------- true: 0x00401349 false: 0x00401340
| 0x00401340 cmp dword [data.0040438c], 0x00 ; [0x40438c:4]=0
| 0x00401347 jz 0x40134a
| ----------- true: 0x0040134a false: 0x00401349
| 0x00401349 int3
| 0x0040134a push str.PASSED. ; 0x403124 ; "PASSED." ; int32_t arg_4h
| 0x0040134f mov esi, dword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x4030b8:4]=0x3884
| 0x00401355 call esi
| 0x00401357 push str.Nested_Exception_test... ; 0x40312c ; "Nested Exception test... " ; int32_t arg_8h
| 0x0040135c call fcn.00401030
| 0x00401361 add esp, 0x08
| 0x00401364 cmp byte [data.00404374], 0x00 ; [0x404374:1]=0
| 0x0040136b jz 0x40136e
| ----------- true: 0x0040136e false: 0x0040136d
| 0x0040136d int3
| 0x0040136e mov dword [data.00404388], 0x01 ; [0x404388:4]=0
| 0x00401378 mov dword [data.0040438c], 0x00 ; [0x40438c:4]=0
| 0x00401382 mov dword [var_30h], 0x01
| 0x00401389 call fcn.00401140
| 0x0040138e mov dword [var_30h], 0xfffffffe ; 4294967294
| 0x00401395 jmp 0x4013d9
| ----------- true: 0x004013d9
| ; CODE XREF from main @ 0x401395
| 0x004013d9 cmp byte [data.00404374], 0x00 ; [0x404374:1]=0
| 0x004013e0 jz 0x4013e3
| ----------- true: 0x004013e3 false: 0x004013e2
| 0x004013e2 int3
| 0x004013e3 cmp dword [data.00404388], 0x368d ; [0x404388:4]=0
| 0x004013ed jnz 0x4013f8
| ----------- true: 0x004013f8 false: 0x004013ef
| 0x004013ef cmp dword [data.0040438c], 0x00 ; [0x40438c:4]=0
| 0x004013f6 jz 0x4013f9
| ----------- true: 0x004013f9 false: 0x004013f8
| 0x004013f8 int3
| 0x004013f9 push str.PASSED. ; 0x403124 ; "PASSED."
| 0x004013fe call esi
| 0x00401400 add esp, 0x04
| 0x00401403 xor eax, eax
| 0x00401405 mov ecx, dword [var_3ch]
| 0x00401408 mov dword fs:[0x0], ecx
| 0x0040140f pop ecx
| 0x00401410 pop edi
| 0x00401411 pop esi
| 0x00401412 pop ebx
| 0x00401413 mov esp, ebp
| 0x00401415 pop ebp
\ 0x00401416 ret
EOF
RUN

View file

@ -4432,3 +4432,92 @@ global uint8_t [4] global_var @ 0x404050
global uint8_t [8] global_array @ 0x404058
EOF
RUN
NAME=x64 structured exception handling xframe
FILE=bins/pe/microsoft_seh_tests/x64/xframe_eh_exe.exe
CMDS=<<EOF
aaa
pdf @ main
EOF
EXPECT=<<EOF
; CALL XREF from entry0 @ 0x1400019cb
/ int main(int argc, char **argv, char **envp);
| 0x140001770 sub rsp, 0x28
| 0x140001774 call fcn.140001590
| 0x140001779 call fcn.140001000
| 0x14000177e call fcn.140001220
| 0x140001783 lea rcx, qword str.Caught_Exceptions_Test_PASSED. ; 0x140003320 ; "Caught Exceptions Test PASSED." ; const char *s
| 0x14000178a call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x1400031a0:8]=0x3e22 ; "\">" ; int puts(const char *s)
| 0x140001790 call fcn.1400016a0
| 0x140001795 lea rcx, qword str.Resumed_Exceptions_Test_PASSED. ; 0x140003340 ; "Resumed Exceptions Test PASSED." ; const char *s
| 0x14000179c call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x1400031a0:8]=0x3e22 ; "\">" ; int puts(const char *s)
| 0x1400017a2 xor eax, eax
| 0x1400017a4 add rsp, 0x28
\ 0x1400017a8 ret
EOF
RUN
NAME=x64 structured exception handling
FILE=bins/pe/seh_x64.exe
CMDS=<<EOF
aaa
pdf @ main
EOF
EXPECT=<<EOF
; CALL XREF from entry0 @ 0x140001433
/ int main(int argc, char **argv, char **envp);
| ; arg int argc @ rcx
| ; arg char **argv @ rdx
| ; var int64_t var_18h @ stack - 0x18
| ; var int64_t var_8h @ stack + 0x8
| 0x140001010 mov qword [var_8h], rbx
| 0x140001015 push rdi
| 0x140001016 sub rsp, 0x30
| 0x14000101a mov rbx, rdx ; argv
| 0x14000101d mov edi, 0xbadbeef
| 0x140001022 cmp ecx, 0x01 ; 1 ; argc
| ,=< 0x140001025 jle 0x140001048
| | 0x140001027 lea rcx, qword str.Writing_to_invalid_pointer. ; 0x140002330 ; "Writing to invalid pointer." ; const char *s
| | 0x14000102e call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x140002180:8]=0x2cbe ; int puts(const char *s)
| | 0x140001034 mov rcx, qword [rbx+0x08] ; const char *str
| | 0x140001038 call qword [sym.imp.api_ms_win_crt_convert_l1_1_0.dll_atoi] ; [0x140002098:8]=0x2ca4 ; int atoi(const char *str)
| | 0x14000103e mov ebx, eax
| | 0x140001040 mov dword [var_18h], eax
| | 0x140001044 mov dword [rdi], eax
| ,==< 0x140001046 jmp 0x14000104c
| |`-> 0x140001048 mov ebx, dword [var_18h]
| | ; CODE XREF from main @ 0x140001046
| `--> 0x14000104c lea rcx, qword str.Try_dividing_by_zero. ; 0x140002350 ; "Try dividing by zero." ; const char *s
| 0x140001053 call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x140002180:8]=0x2cbe ; int puts(const char *s)
| 0x140001059 mov eax, ebx
| 0x14000105b cdq
| 0x14000105c xor ecx, ecx
| 0x14000105e idiv ecx
| 0x140001060 mov dword [var_18h], eax
| ,=< 0x140001064 jmp 0x140001074
| | ; CODE XREF from main @ 0x14000104c
| | 0x140001066 lea rcx, qword str.Inside_nested_except_block ; 0x140002368 ; "Inside nested except block!" ; const char *s
| | 0x14000106d call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x140002180:8]=0x2cbe ; int puts(const char *s)
| | 0x140001073 nop
| | ; CODE XREF from main @ 0x140001064
| ,`-> 0x140001074 jmp 0x1400010a2
| | ; CODE XREF from main @ 0x140001022
| | 0x140001076 lea rcx, qword str.Inside_exception_handler ; 0x140002388 ; "Inside exception handler!\n" ; const char *s
| | 0x14000107d call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x140002180:8]=0x2cbe ; int puts(const char *s)
| | 0x140001083 nop
| | 0x140001084 mov edx, 0xbadbeef ; int64_t arg2
| | 0x140001089 mov ecx, dword [var_18h] ; int64_t arg1
| | 0x14000108d call fcn.140001170
| |,=< 0x140001092 jmp 0x1400010a2
| || ; CODE XREF from main @ 0x140001084
| || 0x140001094 lea rcx, qword str.Divide_by_zero_exception ; 0x1400023a8 ; "Divide by zero exception!" ; const char *s
| || 0x14000109b call qword [sym.imp.api_ms_win_crt_stdio_l1_1_0.dll_puts] ; [0x140002180:8]=0x2cbe ; int puts(const char *s)
| || 0x1400010a1 nop
| || ; CODE XREFS from main @ 0x140001074, 0x140001092
| ``-> 0x1400010a2 xor eax, eax
| 0x1400010a4 mov rbx, qword [var_8h]
| 0x1400010a9 add rsp, 0x30
| 0x1400010ad pop rdi
\ 0x1400010ae ret
EOF
RUN