4

In the program I'm trying to reverse engineer, originally IDA only created three segments: CODE, DATA and .idata.

Using the information from the compiler source code (http://pastebin.com/ParJ3683 lines 30-78), I determined that infact DATA was concatenated out of (at least) four segments, DATA,INITDATA,EXITDATA and BSS.

So I created three new segments with the specified alignments (word/dword) and the appropriate boundaries; while all data appeared in the correct segment bounds, all references to what had been in the DATA segment and is now in BSS are now totally messed up:

CODE:00401A8A                 push    ds:globalErrorMessagesCaption[eax*4] ; lpCaption

turned into

CODE:00401A8A                 push    dword ptr ds:(algn_481049+187h)[eax*4] ; lpCaption

The section header is

_BSS:00481106 ; Segment type: Pure data
_BSS:00481106 _BSS            segment dword public 'DATA' use32
_BSS:00481106                 assume cs:_BSS
_BSS:00481106                 ;org 481106h

What has gone wrong here and how can I fix it?

2 Answers 2

2

Short answer: your newly created segments probably have an invalid selector value of 0, and things should start working again as soon as you set the selector to a valid value (e.g. SetSegmentAttr(here, SEGATTR_SEL, 1) at the command prompt). The reason is that all selectors created by IDA for a PE32(+) have the same base and are mostly equivalent.

Long answer:

There are certain differences between recent IDA versions in the way segment editing via the UI works. Segment editing via the UI can cause complex operations under the hood, and the resulting behaviour is not always intuitive. That's why I'd rather not give a solution in terms of UI operations.

The segment editing functions available in IDC and Python are much simpler and straightforward, and they can be invoked from IDA's command prompt (including symbolic names for flag values, like SEGMOD_KEEP). For trickier stuff I find it most convenient to compose my own operations as named snippets in the code snippet editor (Shift-F2). With a suitable Jump() at the end of the operation - to position the cursor on the most likely candidate for the next operation - this makes it easy to get a lot of stuff done in no time flat.

The IDC/Python segment editing functions are slightly better documented than the whole UI stuff and, being simpler, they are easier to get a handle on by way of experimentation. And much less prone to nasty surprises. If bad things have happened - as in your case - they can often be repaired by probing a working example in one IDA instance with commands like this:

GetSegmentAttr(here, SEGATTR_FLAGS)

and then switching to the other IDA instance containing the 'patient' and poking in the newly discovered value:

SetSegmentAttr(here, SEGATTR_FLAGS, 0x10)

Since both IDA instances share the same command prompt history, entering the second command is as simple as hitting the up arrow and modifying the query that was entered in the other IDA instance. In your case things will probably start working again if you set SEGATTR_SEL for the newly created segments to the same value as an existing (and hence correctly configured) segment. To find the magic flags and their names I prefer grepping $(IDA)/idc/idc.idc over consulting the help file, since idc.idc tends to be more comprehensive and more up to date.

Note: view windows like "Program Segmentation" do not refresh on their own but they can be refreshed by hitting their hotkey again (e.g. Shift-F7 for "Program Segmentation"), and also by entering "RefreshLists()" at the command prompt. Also, all the stuff I wrote here is probably far from optimal, but it's the best I am able to do based on my limited knowledge and existing documentation...

Last but not least, segments are not very significant for PE32(+) targets with their flat address spaces. I find them convenient for tagging ranges of code as belonging to a certain module (e.g. 'CRT', 'Lua', whatever) but it is not really necessary to create a faithful representation of the segments contained in the source code, since they are mostly for the benefit of the linker and end up being merged into a tiny number of PE sections.

1
  • Luckily I did a backup and restored it - how do I do segment splitting with IDC the "proper" way?
    – Skynet
    Dec 30, 2014 at 2:15
0

IDA cannot reference symbols within a segment unless that segment has a valid selector, so that's the most important property to set for a new segment. The selector can be set in the 'Create Segment...' dialogue via the field "base in paragraphs".

GetSegmentAttr(here, SEGATTR_SEL) tells you what the proper selector is, if the cursor is in the segment to be split. You can type the expression right into the input field of the dialogue; by the same token you can type here into the begin address field and SegEnd(here) into the end address field.

Here's an IDC snippet (Shift-F2) that splits the current segment at the current position, cloning most relevant properties (including SEGATTR_SEL):

CompileEx(
  "class HelperFunctions {"
    "copy_seg_attr (src, dst, attr) { SetSegmentAttr(dst, attr, GetSegmentAttr(src, attr)); }"
  "};", 0  );

auto ori_seg, ok, fn;

ori_seg = SegStart(here);

ok = AddSegEx(
   here, 
   SegEnd(here), 
   GetSegmentAttr(here, SEGATTR_SEL),
   GetSegmentAttr(here, SEGATTR_BITNESS),
   GetSegmentAttr(here, SEGATTR_ALIGN),
   GetSegmentAttr(here, SEGATTR_COMB),
   ADDSEG_NOSREG  );

if (!ok)  return Warning("AddSegEx() failed");

fn = HelperFunctions();    
fn.copy_seg_attr(ori_seg, here, SEGATTR_PERM);
fn.copy_seg_attr(ori_seg, here, SEGATTR_FLAGS);
fn.copy_seg_attr(ori_seg, here, SEGATTR_ES);
fn.copy_seg_attr(ori_seg, here, SEGATTR_SS);
fn.copy_seg_attr(ori_seg, here, SEGATTR_DS);
fn.copy_seg_attr(ori_seg, here, SEGATTR_TYPE);
fn.copy_seg_attr(ori_seg, here, SEGATTR_COLOR);

RenameSeg(here, AskStr("", "segment name"));

Note: 'inlining' a class definition via Compile() or CompileEx() was the only trick I found for defining a function inside a snippet. It seems to work only in newer IDAs though (tested with 6.6 and 6.7), and only if the Compile() is right at the start of the snippet.

For older IDA versions the helper function has to be defined in some other way, for example in a separate .idc file, and the call to AddSegEx() needs to be replaced with AddSeg().

Also, I couldn't find a way to query the segment class, and so it cannot be copied even though there is a function SetSegClass() that can set it.

The inverse operation - merging the next segment into the current one - is much simpler:

auto seg_beg, seg_end, next_seg;

seg_beg = SegStart(here);

if (seg_beg == -1)  return Warning("no segment here");

next_seg = NextSeg(here);

if (next_seg == SegEnd(here))
{
   seg_end = SegEnd(next_seg);

   DelSeg(next_seg, SEGMOD_KEEP);
   SetSegBounds(seg_beg, seg_beg, seg_end, SEGMOD_KEEP);

   Jump(PrevNotTail(seg_end));
}

With a snippet like this you can merge a whole boatload of segments with just a single click per segment, which is handy for memory dumps. Or for undoing accidental segment splits...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.