/* * This Loader Module is written by Ilfak Guilfanov and * rewriten by Yury Haron * */ /* L O A D E R pard of MS-DOS file format's (overlayed EXE) */ #include "../idaldr.h" #include #include #include "dos_ovr.h" static const char *const stub_class = "STUBSEG"; static const char *const stub_name_fmt = "stub%03d"; static const char *const ovr_class = "OVERLAY"; static const char *const ovr_name_fmt = "ovr%03d"; static uint32 ovr_off = 0; //------------------------------------------------------------------------ o_type PrepareOverlayType(linput_t *li, exehdr *E) { uint32 flen = qlsize(li); uint32 base = E->HdrSize * 16; uint32 loadend = base + E->CalcEXE_Length(); uint32 fbovoff; fbov_t fbov; ovr_off = 0; for ( fbovoff = (loadend + 0xF) & ~0xF; ; fbovoff += 0x10 ) { if ( pos_read(li, fbovoff, &fbov, sizeof(fbov)) ) break; if ( fbov.fb != FB_MAGIC ) break; if ( fbov.ov == OV_MAGIC ) { ovr_off = fbovoff; return (fbov.exeinfo > loadend || fbov.ovrsize > (flen - fbovoff) || fbov.segnum <= 0) ? ovr_pascal : ovr_cpp; } } exehdr e1; fbovoff = (loadend + 511) & ~511; flen -= fbovoff; if ( !pos_read(li, fbovoff, &e1, sizeof(e1)) && e1.exe_ident == EXE_ID // only MZ ! && flen >= (base = e1.HdrSize*16) && e1.TablOff + (e1.ReloCnt*4) <= (flen -= base) && e1.CalcEXE_Length() <= flen ) { ovr_off = fbovoff; return ovr_ms; } return ovr_noexe; } //------------------------------------------------------------------------ static bool isStubPascal(ea_t ea) { return get_word(ea) == 0x3FCD // int 3F && (int32)get_dword(ea+4) > 0 // fileoff && get_word(ea+8) != 0 // codesize && (short)get_word(ea+10) >= 0 // relsize (assume max 32k) && (short)get_word(ea+12) > 0 // nentries && (short)get_word(ea+12) < (0x7FFF / sizeof(ovrentry_t)) // nentries && is_mapped(to_ea(inf_get_baseaddr() + get_word(ea+14), 0)); // prevstub } //------------------------------------------------------------------------ linput_t *CheckExternOverlays(void) { char buf[MAXSTR]; const char *p; if ( get_input_file_path(buf, sizeof(buf)) <= 0 || (p=strrchr(buf, '.')) == NULL || stricmp(++p, e_exe) != 0 ) { return NULL; } for ( segment_t *s = get_first_seg(); s != NULL; s = get_next_seg(s->start_ea) ) { ea_t ea = s->start_ea; if ( isStubPascal(ea) ) { switch ( ask_yn(ASKBTN_NO, "This file contains reference to Pascal-stype overlays\n" "Do you want to load it?") ) { case ASKBTN_NO: return NULL; case ASKBTN_CANCEL: loader_failure(); default: // Yes break; } while ( true ) { p = ask_file(false, set_file_ext(buf, sizeof(buf), buf, "ovr"), "Please enter pascal overlays file"); CheckCtrlBrk(); if ( p == NULL ) return NULL; linput_t *li = open_linput(p, false); if ( li != NULL ) return li; warning("Pascal style overlays file '%s' is not found", p); } } } return NULL; } //------------------------------------------------------------------------ static void removeBytes(void) { ea_t ea = inf_get_omin_ea(); msg("Deleting bytes which do not belong to any segment...\n"); for ( int i = 0; ; ++i ) { if ( ea >= inf_get_omax_ea() ) break; segment_t *sptr = getnseg(i); if ( ea < sptr->start_ea ) { show_addr(ea); deb(IDA_DEBUG_LDR, "Deleting bytes at %a..%a (they do not belong to any segment)...\n", ea, sptr->start_ea); if ( disable_flags(ea,sptr->start_ea) ) { warning("Maximal number of segments is reached, some bytes are out of segments"); return; } CheckCtrlBrk(); } ea = sptr->end_ea; } } //------------------------------------------------------------------------ static int add_struc_fld( struc_t *st, flags_t flag, size_t sz, const char *name, const char *cmt) { int i = add_struc_member(st, name, BADADDR, flag, NULL, sz); if ( i == 0 && cmt != NULL ) set_member_cmt(get_member_by_name(st, name), cmt, false); return i; } //------------------------------------------------------ static void describeStub(ea_t stubEA) { static const char stubSname[] = "_stub_descr"; static tid_t id = 0; if ( id == 0 && (id=get_struc_id(stubSname)) == BADNODE ) { struc_t *st = get_struc(add_struc(BADADDR, stubSname)); if ( st == NULL ) goto badst; st->props |= SF_NOLIST; if ( add_struc_fld(st, byte_flag()|hex_flag(), 2, "int_code", "Overlay manager interrupt") || add_struc_fld(st, word_flag()|hex_flag(), sizeof(short), "memswap", "Runtime memory swap address") || add_struc_fld(st, dword_flag()|hex_flag(), sizeof(int32), "fileoff", "Offset in the file to the code") || add_struc_fld(st, word_flag()|hex_flag(), sizeof(short), "codesize", "Code size") || add_struc_fld(st, word_flag()|hex_flag(), sizeof(short), "relsize", "Relocation area size") || add_struc_fld(st, word_flag()|dec_flag(), sizeof(short), "nentries", "Number of overlay entries") || add_struc_fld(st, word_flag()|seg_flag(), sizeof(short), "prevstub", "Previous stub") || add_struc_fld(st, byte_flag()|hex_flag(), STUBUNK_SIZE, "workarea", NULL) ) { badst: warning("Failed to create stub structure descriptor"); id = BADNODE; } else { array_parameters_t apt; apt.flags = AP_ALLOWDUPS; apt.lineitems = 8; apt.alignment = -1; // nonalign set_array_parameters(get_member_id(st, 0), &apt); set_array_parameters(get_member_id(st,offsetof(stub_t,unknown)), &apt); // st->props |= SF_NOLIST; // save_struc(st, true); id = st->id; } } ushort tmp = get_word(stubEA + offsetof(stub_t, prevstub)); if ( tmp != 0 ) put_word(stubEA + offsetof(stub_t, prevstub), uint16(tmp + inf_get_baseaddr())); tmp = get_word(stubEA + offsetof(stub_t, nentries)); if ( id != BADNODE ) { del_items(stubEA, DELIT_EXPAND, sizeof(stub_t)); create_struct(stubEA, sizeof(stub_t), id); } stubEA += sizeof(stub_t); if ( tmp != 0 ) { do { auto_make_proc(stubEA); stubEA += 5; CheckCtrlBrk(); } while ( --tmp ); } } //------------------------------------------------------------------------ static void load_overlay( linput_t *li, uint32 exeinfo, ea_t stubEA, segment_t *s, qoff64_t fboff) { ea_t entEA = stubEA + sizeof(stub_t); stub_t stub; if ( get_bytes(&stub, sizeof(stub), stubEA) != sizeof(stub) ) errstruct(); msg("Overlay stub at %a, code at %a...\n", stubEA, s->start_ea); if ( stub.CDh != 0xCD ) errstruct(); // bad stub // i now load overlay code: bool waszero = false; if ( !stub.codesize ) // IDA doesn't allow 0 length segments { ++stub.codesize; waszero = true; } s->end_ea = s->start_ea + stub.codesize; file2base(li, fboff+stub.fileoff, s->start_ea, s->end_ea, fboff == 0 ? FILEREG_NOTPATCHABLE : FILEREG_PATCHABLE); if ( waszero ) { s->type = SEG_NULL; stub.codesize = 0; } uint i; for ( i = 0; i < stub.nentries; ++i ) { show_addr(entEA); put_byte(entEA, 0xEA); // jmp far ushort offset = get_word(entEA+2); put_word(entEA+1, offset); // offset put_word(entEA+3, s->sel); // selector auto_make_proc(to_ea(sel2para(s->sel), offset)); entEA += sizeof(ovrentry_t); CheckCtrlBrk(); } qoff64_t fpos = fboff + stub.fileoff + stub.codesize; qlseek(li, fpos); fixup_data_t fd(FIXUP_SEG16); uint relcnt = stub.relsize / 2; validate_array_count(li, &relcnt, sizeof(ushort), "Relocation count", fpos); if ( relcnt != 0 ) { ushort *relb = qalloc_array(relcnt); if ( !relb ) nomem("overlay relocation table"); lread(li, relb, sizeof(ushort)*relcnt); int32 pos = qltell(li); // must?? ushort *relc = relb; do { if ( *relc > stub.codesize ) errstruct(); ea_t xEA = s->start_ea + *relc++; show_addr(xEA); ushort relseg = get_word(xEA); if ( exeinfo != 0 ) { seginfo_t si; if ( pos_read(li, exeinfo + relseg, &si, sizeof(si)) ) errstruct(); relseg = si.seg; } fd.sel = relseg + inf_get_baseaddr(); fd.set(xEA); put_word(xEA, ushort(fd.sel)); CheckCtrlBrk(); } while ( --relcnt ); qfree(relb); qlseek(li, pos); } } //------------------------------------------------------------------------ static void add_seg16(ea_t ea) { segment_t s; s.sel = ea >> 4; s.start_ea = ea; s.end_ea = BADADDR; s.align = saRelByte; s.comb = scPub; add_segm_ex(&s, NULL, NULL, ADDSEG_NOSREG | ADDSEG_SPARSE); } //------------------------------------------------------------------------ static sel_t AdjustStub(ea_t ea) // returns prev stub { segment_t *seg = getseg(ea); if ( ea != seg->start_ea ) add_seg16(ea); ushort nentries = get_word(ea+12); uint32 segsize = sizeof(stub_t) + nentries * sizeof(ovrentry_t); seg = getseg(ea); asize_t realsize = seg->end_ea - seg->start_ea; if ( segsize > realsize ) return BADSEL; // this stub is bad if ( segsize != realsize ) { ea_t next = seg->start_ea + segsize; set_segm_end(seg->start_ea, next, 0); next += 0xF; next &= ~0xF; if ( is_mapped(next) ) { segment_t *s = getseg(next); if ( s == NULL ) add_seg16(next); } } return get_word(ea + 14); } //------------------------------------------------------------------------ void LoadPascalOverlays(linput_t *li) { // AdjustPascalOverlay ea_t minea = inf_get_min_ea(); ea_t maxea = inf_get_max_ea(); for ( ea_t ea = minea; ea < maxea; ) { ea &= ~0xF; if ( isStubPascal(ea) ) { AdjustStub(ea); ea = getseg(ea)->end_ea; ea += 0xF; CheckCtrlBrk(); } else { ea += 0x10; } } //- ea_t ea; int i = 0; for ( segment_t *s0 = get_first_seg(); s0 != NULL; s0 = get_next_seg(ea), ++i ) { ea = s0->start_ea; if ( get_byte(ea) != 0xCD || get_byte(ea+1) != 0x3F ) continue; set_segm_class(s0, stub_class); char sname[32]; qsnprintf(sname, sizeof(sname), stub_name_fmt, i); set_segm_name(s0, sname); segment_t s; s.comb = scPub; s.align = saRelPara; s.start_ea = (inf_get_max_ea() + 0xF) & ~0xF; s.sel = setup_selector(s.start_ea >> 4); // 04.06.99 ig: what is exeinfo and why it is passed as 0 here? load_overlay(li, 0/*???*/, ea, &s, ovr_off); // i qsnprintf(sname, sizeof(sname), ovr_name_fmt, i); if ( !add_segm_ex(&s, sname, ovr_class, ADDSEG_NOSREG|ADDSEG_SPARSE) ) loader_failure(); describeStub(ea); CheckCtrlBrk(); } removeBytes(); } //------------------------------------------------------------------------ static ea_t CppInfoBase(fbov_t *fbov) { seginfo_t si; ea_t siEA = get_fileregion_ea(fbov->exeinfo); if ( siEA == BADADDR || get_bytes(&si, sizeof(si), siEA) != sizeof(si) ) { errstruct(); } if ( (si.flags & SI_OVR) && si.seg ) // possible truncation { ushort lseg = si.seg; msg("Probbly the input file was truncated by 'unp -h'. Searching the base...\n"); do { if ( si.seg > lseg ) errstruct(); lseg = si.seg; if ( siEA < inf_get_omin_ea()+sizeof(si) || get_bytes(&si, sizeof(si), siEA -= sizeof(si)) != sizeof(si) ) { errstruct(); } fbov->exeinfo -= sizeof(si); CheckCtrlBrk(); } while ( si.seg ); add_pgm_cmt("Real (before unp -h) EXEinfo=%08X", fbov->exeinfo); } return siEA; } //------------------------------------------------------------------------ sel_t LoadCppOverlays(linput_t *li) { fbov_t fbov; sel_t dseg = BADSEL; if ( pos_read(li, ovr_off, &fbov, sizeof(fbov)) ) errstruct(); add_pgm_cmt("Overlays: base=%08X, size=%08X, EXEinfo=%08X", ovr_off, fbov.ovrsize, fbov.exeinfo); ovr_off += sizeof(fbov_t); if ( fbov.segnum == 0 ) errstruct(); ea_t siEA = CppInfoBase(&fbov); ushort lseg = 0; for ( int32 i = 0; i < fbov.segnum; ++i ) { seginfo_t si; if ( get_bytes(&si, sizeof(si), siEA) != sizeof(si) ) errstruct(); siEA += sizeof(si); if ( si.maxoff == 0xFFFF ) continue; // skip EXEINFO & OVRDATA if ( si.maxoff <= si.minoff ) continue; if ( si.seg < lseg ) errstruct(); lseg = si.seg; si.seg += (ushort)inf_get_baseaddr(); const char *sclass = NULL; segment_t s; // i initialize segment_t with 0s s.align = saRelByte; s.comb = scPub; if ( si.seg == inf_get_start_ss() ) { sclass = CLASS_STACK; s.type = SEG_DATA; s.comb = scStack; } if ( si.flags & SI_COD ) { sclass = CLASS_CODE; s.type = SEG_CODE; } if ( si.flags & SI_DAT ) { sclass = CLASS_BSS; s.type = SEG_DATA; dseg = si.seg; } s.name = 0; if ( si.flags & SI_OVR ) { s.align = saRelPara; s.start_ea = (inf_get_max_ea() + 0xF) & ~0xF; s.sel = setup_selector(s.start_ea >> 4); // i end_ea is set in load_overlay() load_overlay(li, fbov.exeinfo, to_ea(si.seg, 0), &s, ovr_off); if ( s.type != SEG_NULL ) s.type = SEG_CODE; char sname[32]; qsnprintf(sname, sizeof(sname), ovr_name_fmt, i); if ( !add_segm_ex(&s, sname, ovr_class, ADDSEG_NOSREG|ADDSEG_SPARSE) ) loader_failure(); s.name = 0; s.type = SEG_NORM; // undefined segment type sclass = stub_class; } s.sel = si.seg; s.start_ea = to_ea(s.sel, si.minoff); s.end_ea = to_ea(s.sel, si.maxoff); if ( !add_segm_ex(&s, NULL, sclass, ADDSEG_NOSREG|ADDSEG_SPARSE) ) loader_failure(); if ( si.flags & SI_OVR ) { describeStub(s.start_ea); char sname[32]; qsnprintf(sname, sizeof(sname), stub_name_fmt, i); set_segm_name(&s, sname); } CheckCtrlBrk(); } removeBytes(); return dseg; } //------------------------------------------------------------------------ //+ //------------------------------------------------------------------------ static netnode msnode; struct modsc_t { uint32 bpos; uint32 size; ushort Toff; ushort Hsiz; ushort Rcnt; ushort Mpara; }; static ea_t ref_off_EA; static ea_t ref_ind_EA; static uint ref_oi_cnt; //------------------------------------------------------------------------ static uint CreateMsOverlaysTable(linput_t *li, bool *PossibleDynamic) { modsc_t o; uint Count = 0; uint32 flen = qlsize(li); o.bpos = ovr_off; msnode.create(); msg("Searching for the overlays in the file...\n"); while ( o.bpos + sizeof(exehdr) < flen ) { exehdr E; uint32 delta; if ( pos_read(li, o.bpos, &E, sizeof(E)) ) errstruct(); o.size = E.CalcEXE_Length(); delta = (uint32)(o.Hsiz = E.HdrSize) * 16; o.Toff = E.TablOff; o.Rcnt = E.ReloCnt; o.Mpara = (ushort)((o.size + 0xF) >> 4); uint32 ost = flen - o.bpos; if ( E.exe_ident != EXE_ID // only MZ ! || ost < delta || (uint32)o.Toff + (E.ReloCnt*4) > (ost -= delta) || o.size > ost ) { return Count; } CheckCtrlBrk(); msnode.supset(++Count, &o, sizeof(o)); ovr_off = o.bpos + delta + o.size; uint32 d2 = align_up(ovr_off, 512); if ( o.bpos == d2 ) { warning("Too small overflay size %u, stopped processing them", delta+o.size); break; } o.bpos = d2; if ( E.Overlay != Count ) *PossibleDynamic = false; } ovr_off = 0; return Count; } //------------------------------------------------------------------------ static void LoadMsOvrData(linput_t *li, uint Count, bool Dynamic) { fixup_data_t fd(FIXUP_SEG16); for ( uint i = 1; i <= Count; ++i ) { modsc_t o; // skip dropped overlays if ( msnode.supval(i, &o, sizeof(o)) != sizeof(o) ) continue; segment_t s; s.comb = scPub; s.align = saRelPara; s.start_ea = (inf_get_max_ea() + 0xF) & ~0xF; s.sel = setup_selector(s.start_ea >> 4); msnode.altset(i, s.sel); s.end_ea = s.start_ea + ((uint32)o.Mpara << 4); file2base(li, o.bpos + o.Hsiz*16LL, s.start_ea, s.start_ea + o.size, FILEREG_PATCHABLE); char sname[32]; qsnprintf(sname, sizeof(sname), ovr_name_fmt, i); if ( !add_segm_ex(&s, sname, ovr_class, ADDSEG_NOSREG|ADDSEG_SPARSE) ) loader_failure(); qlseek(li, o.bpos + o.Toff); for ( uint j = o.Rcnt; j; --j ) { ushort buf[2]; lread(li, buf, sizeof(buf)); // ATTENTION!!! if Dynamic (ms-autopositioning) segment part of relocation // address == pseudodata segment to load (from data in ovr!) // We should checked it but don't have any testcase ea_t xEA = Dynamic ? s.start_ea + buf[0] : s.start_ea + to_ea(buf[1], buf[0]); if ( xEA >= s.end_ea ) errstruct(); show_addr(xEA); ushort ubs = ushort(get_word(xEA) + inf_get_baseaddr()); put_word(xEA, ubs); fd.sel = ubs; fd.set(xEA); add_segm_by_selector(ubs, CLASS_CODE); CheckCtrlBrk(); } } } //------------------------------------------------------------------------ static sel_t SearchMsOvrTable(uint *Cnt) { modsc_t dsc; if ( msnode.supval(1, &dsc, sizeof(dsc)) != sizeof(dsc) ) { interr: error("Internal error"); } uint32 src[2] = { 0, dsc.bpos }; ea_t dstea, sea, ea = inf_get_min_ea(); uint AddSkip, Count = *Cnt; uint i, j; // watcom ... segment_t *s; msg("Searching the overlay reference data table...\n"); while ( ea + sizeof(src) < inf_get_max_ea() && (sea = bin_search2(ea, inf_get_max_ea(), (uchar *)src, NULL, sizeof(src), BIN_SEARCH_CASE | BIN_SEARCH_NOBREAK | BIN_SEARCH_FORWARD)) != BADADDR ) { ea = sea + sizeof(uint32); s = getseg(ea); if ( s == NULL || ea - s->start_ea < sizeof(uint32)*(Count+1) || ea + (2*sizeof(uint32) * Count) > s->end_ea ) { nextfndadd: ea += sizeof(uint32); nextfnd: continue; } AddSkip = 0; for ( i = 2; i <= Count + AddSkip; ++i ) { ea += sizeof(uint32); uint32 pos = get_dword(ea); if ( pos == 0 ) { ++AddSkip; if ( ea + (2*sizeof(uint32) * (Count+AddSkip-i)) > s->end_ea ) goto nextfnd; } else { if ( msnode.supval(i - AddSkip, &dsc, sizeof(dsc)) != sizeof(dsc) ) goto interr; if ( pos != dsc.bpos ) goto nextfndadd; } } goto found; } badtable: ref_oi_cnt = (uint)-1; return BADSEL; found: if ( AddSkip ) { ea = sea + sizeof(uint32); for ( i = 2; i <= Count; ++i ) { if ( !get_dword(ea += sizeof(uint32)) ) { if ( !AddSkip ) goto interr; --AddSkip; for ( j = Count; j >= i; --j ) { if ( msnode.supval(j, &dsc, sizeof(dsc)) != sizeof(dsc) ) goto interr; msnode.supset(j+1, &dsc, sizeof(dsc)); } msnode.supdel(i); ++Count; CheckCtrlBrk(); } } if ( AddSkip ) goto interr; } //msg("Found disk blocks table\n"); ea = sea - ((Count-1) * sizeof(ushort)) - 1; // -1 -- unification do { ea = bin_search2(s->start_ea, ea+1, (uchar *)src, NULL, sizeof(ushort), BIN_SEARCH_CASE | BIN_SEARCH_NOBREAK | BIN_SEARCH_BACKWARD); if ( ea == BADADDR ) goto badtable; } while ( (sea - ea) % sizeof(ushort) ); ref_oi_cnt = (sea - ea) / sizeof(ushort); if ( ref_oi_cnt <= 1 ) goto badtable; ref_ind_EA = ea; //msg("Check all tables...\n"); j = Count; while ( (ea += sizeof(ushort)) < sea ) { i = get_word(ea); if ( i > j ) { if ( j == *Cnt ) goto badtable; j = i; } } if ( (i = j - Count) != 0 ) { AddSkip = i; do { if ( get_dword(sea - sizeof(uint32)) ) break; if ( (ref_oi_cnt -= 2) <= 1 ) goto badtable; sea -= sizeof(uint32); } while ( --i ); AddSkip -= i; for ( j = Count; j; --j ) { if ( msnode.supval(j, &dsc, sizeof(dsc)) != sizeof(dsc) ) msnode.supdel(j + AddSkip); else msnode.supset(j + AddSkip, &dsc, sizeof(dsc)); } do { msnode.supdel(++j); } while ( j < AddSkip ); Count += AddSkip; CheckCtrlBrk(); if ( i ) { ea = sea + Count*sizeof(uint32); Count += i; do { if ( get_dword(ea += sizeof(uint32)) ) goto badtable; } while ( --i ); } } dstea = sea; ea = ref_ind_EA - (ref_oi_cnt*sizeof(ushort)); if ( get_prev_fixup_ea(ea+1) != ea ) ask_for_feedback("Absent relocation at start of offset table"); ref_off_EA = ea; sea = ref_ind_EA; AddSkip = 0; // added 07.04.2015 (bmpcad) for ( i = 1; i < ref_oi_cnt; ++i ) { ea += sizeof(ushort); sea += sizeof(ushort); uint rsz; j = get_word(sea); if ( !j ) { if ( i <= Count ) goto badofftb; ++AddSkip; continue; } rsz = get_word(ea); if ( msnode.supval(j, &dsc, sizeof(dsc)) != sizeof(dsc) ) { if ( rsz ) goto badofftb; msg("An overlay index %u in the table of indexes points to a missing overlay\n", i); } else if ( rsz >= dsc.size ) { badofftb: ask_for_feedback("Incompatible offset table"); AddSkip = 0; break; } } sea = dstea + (Count+1+AddSkip)*sizeof(uint32); for ( i = 1; i <= Count; ++i ) { sea += sizeof(uint32); uint32 dt = get_dword(sea); if ( msnode.supval(i, &dsc, sizeof(dsc)) != sizeof(dsc) ) { if ( dt ) { badmemtb: ask_for_feedback("Incompatible mem-size table"); } continue; } if ( !dt ) { ask_for_feedback("Zero overlay memory size in description table"); goto badtable; } if ( dt < dsc.Mpara || dt >= 0x1000 ) goto badmemtb; // Possiblee needed for segment with unitialized data at top, but not sampled... if ( dt > dsc.Mpara ) { dsc.Mpara = (ushort)dt; msnode.supset(i, &dsc, sizeof(dsc)); } } for ( i = 0; i < AddSkip; i++ ) { sea += sizeof(uint32); if ( get_dword(sea) != 0 ) { ask_for_feedback("Incompatible extension in overlay tables"); break; } } msg("All tables OK\n"); create_word(ref_off_EA, i = (ref_oi_cnt - AddSkip)*sizeof(ushort)); force_name(ref_off_EA, "ovr_off_tbl"); create_word(ref_ind_EA, i); force_name(ref_ind_EA, "ovr_index_tbl"); *Cnt = Count; i = (Count + 1) * sizeof(uint32); create_dword(dstea, i); force_name(dstea, "ovr_start_tbl"); dstea += i + (AddSkip * sizeof(uint32)); create_dword(dstea, i); force_name(dstea, "ovr_memsiz_tbl"); return s->sel; } //------------------------------------------------------------------------ static segment_t *MsOvrStubSeg(uint *stub_cnt, ea_t r_top, sel_t dseg) { msg("Searching for the stub segment...\n"); int count = get_segm_qty(); for ( int i = 0; i < count; ++i ) { segment_t *seg = getnseg(i); if ( seg->sel == dseg ) continue; ea_t ea = seg->start_ea; uchar buf[3*sizeof(ushort)]; if ( ea >= r_top ) break; if ( get_bytes(buf, sizeof(buf), ea) != sizeof(buf) ) continue; if ( *(uint32 *)buf || *(ushort *)&buf[sizeof(uint32)] ) continue; uint cnt = 0; uchar frs = (uchar)-1; while ( (ea += sizeof(buf)) < seg->end_ea - sizeof(buf) ) { if ( (frs = get_byte(ea)) != 0xCD || get_byte(ea+1) != 0x3F ) break; ushort ind = get_word(ea + sizeof(ushort)); if ( !ind || ind > ref_oi_cnt ) break; ++cnt; CheckCtrlBrk(); } if ( !frs && cnt >= ref_oi_cnt ) { *stub_cnt = cnt; return seg; } } return NULL; } //------------------------------------------------------------------------ static void CreateMsStubProc(segment_t *s, uint stub_cnt) { ea_t ea = s->start_ea; set_segm_name(s, "STUB"); set_segm_class(s, CLASS_CODE); create_byte(ea, 3*sizeof(ushort)); ea += 3*sizeof(ushort); msg("Patching the overlay stub-segment...\n"); for ( uint ind, i = 0; i < stub_cnt; ++i, ea += 3*sizeof(ushort) ) { ind = get_word(ea+2); if ( ind != 0 ) { if ( ind >= ref_oi_cnt ) { badref: ask_for_feedback("Illegal reference in overlay call interrupt"); continue; } ind *= sizeof(ushort); uint off = (uint)get_word(ea+4) + get_word(ref_off_EA + ind); ind = get_word(ref_ind_EA + ind); // overlay number ushort sel = (ushort)msnode.altval(ind); modsc_t o; if ( msnode.supval(ind, &o, sizeof(o)) != sizeof(o) ) goto badref; if ( off >= o.size ) goto badref; show_addr(ea); put_byte(ea, 0xEA); // jmp far put_word(ea+1, off); // offset put_word(ea+3, sel); // selector put_byte(ea+5, 0x90); // NOP -> for autoanalisis auto_make_proc(ea); auto_make_proc(to_ea(sel2para(sel), off)); CheckCtrlBrk(); } } create_align(ea, s->end_ea - ea, 0); } //------------------------------------------------------------------------ sel_t LoadMsOverlays(linput_t *li, bool PossibleDynamic) { sel_t dseg = BADSEL; uint Cnt = CreateMsOverlaysTable(li, &PossibleDynamic); if ( ovr_off ) warning("File has extra information\n" "\3Loading 0x%X bytes, total file size 0x%" FMT_64 "X", ovr_off, qlsize(li)); if ( Cnt ) { dseg = SearchMsOvrTable(&Cnt); if ( dseg != BADSEL ) PossibleDynamic = false; else if ( !PossibleDynamic ) ask_for_feedback("Cannot find the overlay call data table"); ea_t r_top = inf_get_max_ea(); LoadMsOvrData(li, Cnt, PossibleDynamic); if ( ref_oi_cnt != (uint)-1 ) { uint stub_cnt; segment_t *s = MsOvrStubSeg(&stub_cnt, r_top, dseg); if ( s != NULL ) CreateMsStubProc(s, stub_cnt); else ask_for_feedback("The overlay-manager segment not found"); } } msnode.kill(); return dseg; }