static void dump_stack_not_using_EBP (process *p, thread *t, CONTEXT *ctx, MemoryCache *mc) { HANDLE THDL=t->THDL; address stack_top=TIB_get_stack_top (THDL, mc); address stack_bottom=TIB_get_stack_bottom (THDL, mc); //strbuf sb=STRBUF_INIT; address SP_at_start=CONTEXT_get_SP(ctx); L ("Call stack:\n"); if (thread_c_debug) L ("SP_at_start=0x%x, stack_top=0x%x, stack_bottom=0x%x\n", SP_at_start, stack_top, stack_bottom); for (address a=SP_at_start; a<stack_top; a=a+sizeof(REG)) { REG r; if (MC_ReadREG(mc, a, &r)) { //L ("r=0x" PRI_REG_HEX "\n", r); if (adr_in_executable_section(p, r)) { strbuf sb=STRBUF_INIT; process_get_sym (p, r, true, true, &sb); L ("(SP+0x%x) return address=0x" PRI_ADR_HEX " (%s)\n", a-SP_at_start, r, sb.buf); strbuf_deinit(&sb); }; }; }; };
static void dump_stack_EBP_frame (process *p, thread *t, CONTEXT * ctx, MemoryCache *mem) { HANDLE THDL=t->THDL; address stack_top=TIB_get_stack_top (THDL, mem); address stack_bottom=TIB_get_stack_bottom (THDL, mem); strbuf sb=STRBUF_INIT; L ("Call stack:\n"); address next_BP=CONTEXT_get_BP (ctx); if (TIB_is_ptr_in_stack_limits (THDL, next_BP, mem)==false) { L ("Current frame pointer %s (0x" PRI_ADR_HEX ") is not within current stack limits (top=0x" PRI_ADR_HEX ", bottom=0x" PRI_ADR_HEX ")\n", BP_REGISTER_NAME, CONTEXT_get_BP (ctx), stack_top, stack_bottom); goto exit; }; while (next_BP<=stack_top && next_BP>=stack_bottom) { REG tmp; bool b=MC_ReadREG(mem, next_BP, &tmp); oassert (b); address ret_adr; b=MC_ReadREG(mem, next_BP+sizeof(REG), &ret_adr); oassert (b); if (ret_adr==0) break; strbuf_reinit(&sb, 0); process_get_sym (p, ret_adr, true, true, &sb); L ("return address=0x" PRI_ADR_HEX " (%s)\n", ret_adr, sb.buf); if (next_BP==tmp) break; next_BP=tmp; }; exit: strbuf_deinit (&sb); };
bool DO_POP (CONTEXT * ctx, MemoryCache *mem, REG *outval) { bool b=MC_ReadREG (mem, CONTEXT_get_SP(ctx), outval); if (b==false) return false; REG new_SP=CONTEXT_get_SP(ctx)+sizeof(REG); CONTEXT_set_SP(ctx, new_SP); return true; };
void check_SEH4_cookie(struct MemoryCache *mc, address adr_of_EBP, address CookieOffset, address CookieXOROffset, REG security_cookie, const char *name) { REG value_in_stack=0; // CookieOffset is a distance between stack frame begin and ebp^security_cookie address adr_in_stack=adr_of_EBP + CookieOffset; if (MC_ReadREG(mc, adr_in_stack, &value_in_stack)==false) { L ("%s() cannot read at %sCookieOffset+EBP (0x" PRI_ADR_HEX ")\n", __FUNCTION__, name, adr_in_stack); return; }; // CookieXOROffset is additional difference between ebp^security_cookie value and what is // stored in the stack REG shifted_EBP=CookieXOROffset + adr_of_EBP; if ((security_cookie^shifted_EBP) != value_in_stack) { L ("%s security cookie is not correct\n", name); L ("%s() adr_in_stack=0x" PRI_ADR_HEX " value_in_stack=0x" PRI_REG_HEX " adr_of_EBP=0x" PRI_REG_HEX " shifted_EBP=0x" PRI_REG_HEX "\n", __FUNCTION__, adr_in_stack, value_in_stack, adr_of_EBP, shifted_EBP); L ("%s() security_cookie=0x" PRI_REG_HEX "\n", __FUNCTION__, security_cookie); }; };
// returns address of next SEH frame address dump_SEH_frame (fds* s, struct process* p, struct thread* t, struct MemoryCache *mc, address a) { struct my_EXCEPTION_REGISTRATION current_SEH_frame; bool b; b=MC_ReadBuffer (mc, a, sizeof(struct my_EXCEPTION_REGISTRATION), (BYTE*)¤t_SEH_frame); if (b==false) { L ("%s() cannot read current SEH frame\n", __FUNCTION__); return REG_MAX; }; strbuf sb=STRBUF_INIT; process_get_sym (p, current_SEH_frame.handler, true /* add_module_name */, true /* add_offset */, &sb); L ("* SEH frame at 0x" PRI_ADR_HEX " prev=0x" PRI_ADR_HEX " handler=0x" PRI_ADR_HEX " (%s)\n", a, current_SEH_frame.prev, current_SEH_frame.handler, sb.buf); bool SEH3=false, SEH4=false; if (string_is_ends_with (sb.buf, "except_handler3")) SEH3=true; REG security_cookie; bool security_cookie_known=false; if (string_is_ends_with (sb.buf, "except_handler4")) { SEH4=true; struct module *m=find_module_for_address(p, current_SEH_frame.handler); if (m->security_cookie_adr_known) { b=MC_ReadREG (mc, m->security_cookie_adr, &security_cookie); if (b==false) L ("%s() can't read security_cookie at 0x" PRI_ADR_HEX " for %s\n", __FUNCTION__, m->security_cookie_adr, get_module_name (m)); else security_cookie_known=true; } else { L ("SEH4 frame is here, but address of security_cookie is not known\n"); L ("Try to place .PDB or .MAP file here with this symbol in it\n"); }; }; if (SEH3==false && SEH4==false) goto exit; struct my_VC_EXCEPTION_REGISTRATION_RECORD current_SEH3_frame; b=MC_ReadBuffer (mc, a, sizeof(struct my_VC_EXCEPTION_REGISTRATION_RECORD), (BYTE*)¤t_SEH3_frame); if (b==false) { L ("%s() cannot read current SEH3/4 frame\n", __FUNCTION__); return REG_MAX; }; int previous_trylevel=current_SEH3_frame.previous_trylevel; L ("SEH%d frame. previous trylevel=%d\n", SEH3 ? 3 : 4, previous_trylevel); address scopetable_address=current_SEH3_frame.scopetable; if (SEH4 && security_cookie_known) { scopetable_address^=security_cookie; struct my_EH4_SCOPETABLE_HEADER EH4_header; b=MC_ReadBuffer (mc, scopetable_address, sizeof(struct my_EH4_SCOPETABLE_HEADER), (BYTE*)&EH4_header); if (b==false) { L ("%s() cannot read current SEH4 frame header. scopetable_address=0x" PRI_ADR_HEX "\n", __FUNCTION__, scopetable_address); return REG_MAX; }; L ("SEH4 header:\tGSCookieOffset=0x%x GSCookieXOROffset=0x%x\n", EH4_header.GSCookieOffset, EH4_header.GSCookieXOROffset); L ("\t\tEHCookieOffset=0x%x EHCookieXOROffset=0x%x\n", EH4_header.EHCookieOffset, EH4_header.EHCookieXOROffset); unsigned adr_of_EBP=a + ((byte*)¤t_SEH3_frame.EBP - (byte*)¤t_SEH3_frame.prev); if (EH4_header.EHCookieOffset!=-2) check_SEH4_cookie (mc, adr_of_EBP, EH4_header.EHCookieOffset, EH4_header.EHCookieXOROffset, security_cookie, "EH"); if (EH4_header.GSCookieOffset!=-2) check_SEH4_cookie (mc, adr_of_EBP, EH4_header.GSCookieOffset, EH4_header.GSCookieXOROffset, security_cookie, "GS"); scopetable_address+=sizeof(struct my_EH4_SCOPETABLE_HEADER); }; if (previous_trylevel>=0 && (SEH3 || (SEH4 && security_cookie_known))) dump_scopetable(mc, p, scopetable_address, previous_trylevel+1); exit: strbuf_deinit (&sb); return current_SEH_frame.prev; };
// idx may be negative bool read_REG_from_stack (MemoryCache *mc, CONTEXT *ctx, int idx, REG * out) { address SP=CONTEXT_get_SP(ctx); return MC_ReadREG (mc, SP + idx*sizeof(REG), out); };