gods
Reversing gods
     
Andrew Schulman's utilities (~1~)
(source code and compiled exe)



courtesy of fravia's pages of reverse engineering
The relevance of the following utilities, both in order to deepen your reversing studies, and to better understand code cannot be enough underlined.
The learner will find treasures understanding, using and modifying reversers' tools.
The more fortunates among you will be able to find the old "Undocumented windows, a programmer's guide to reserved Micro$oft windows API functions", by Andrew Schulman, David Maxey and Matt Pietrek (yep!: Pietrek, nonetheless) in your favourite second hand bookshop. Those that know how to search will find the whole book on line as well.
Read the following code, use it (ideally loading the source into Softice when executing) and ameliorate it for our holy reversing purposes!
Enjoy!

On this page you'll find the following utilities:
[mem one] ~ [mem two] ~


mem1

/* 

MEM1.C -- walks DOS MCB chain(s): detailed version

Andrew Schulman and Jim Kyle, July 1990

*/



#include <stdlib.h>

#include <stdio.h>

#include <ctype.h>

#include <string.h>

#include <dos.h>



typedef enum { FALSE, TRUE } BOOL;

typedef unsigned char BYTE;

typedef unsigned short WORD;

typedef unsigned long ULONG;

typedef void far *FP;



#ifndef MK_FP

#define MK_FP(seg,ofs)  ((FP)(((ULONG)(seg) << 16) | (ofs)))

#endif



#ifdef __TURBOC__

#define ASM asm

#else

#define ASM _asm

#endif



#ifdef __TURBOC__

#define GETVECT(x)      getvect(x)

#else

#define GETVECT(x)      _dos_getvect(x)

#endif



#pragma pack(1)



typedef struct {

    BYTE type;          /* 'M'=in chain; 'Z'=at end */

    WORD owner;         /* PSP of the owner */

    WORD size;          /* in 16-byte paragraphs */

    BYTE unused[3];

    BYTE dos4[8];

    } MCB;



#define MCB_FM_SEG(seg)     ((seg) - 1)

#define IS_PSP(mcb)         (FP_SEG(mcb) + 1 == (mcb)->owner)

#define ENV_FM_PSP(psp_seg) (*((WORD far *) MK_FP(psp_seg, 0x2c)))



void fail(char *s) { puts(s); exit(1); }



BOOL belongs(void far *vec, unsigned start, unsigned size);

void display(MCB far *mcb);

char far *env(MCB far *mcb);

void display_progname(MCB far *mcb);

void display_cmdline(MCB far *mcb);

void display_vectors(MCB far *mcb);

unsigned fstrlen(char far *s);



MCB far *get_mcb(void)

{

    ASM mov ah, 52h

    ASM int 21h

    ASM mov dx, es:[bx-2]

    ASM xor ax, ax

    /* in both Microsoft C and Turbo C, far* returned in DX:AX */

}



mcb_chk(MCB far *mcb)

{

    for (;;)

        if (mcb->type == 'M')

            mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);

        else

            return (mcb->type == 'Z');

}



void walk(MCB far *mcb)

{

    printf("Seg     Owner   Size\n"); 

    for (;;)

        switch (mcb->type)

        {

            case 'M' : /* Mark : belongs to MCB chain */

                display(mcb);

                mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);

                break;

            case 'Z' : /* Zbikowski : end of MCB chain */

                display(mcb);

                return;

            default :

                fail("error in MCB chain");

        }

}



main(int argc, char *argv[])

{

    if (argc < 2)

        walk(get_mcb());            /* walk "normal" MCB chain */

    else

    {

        unsigned seg;

        sscanf(argv[1], "%04X", &seg);

        walk(MK_FP(seg, 0));       /* walk arbitrary MCB chain */

    }



    return 0;

}



void display(MCB far *mcb)

{

    static void far *vect_2e = (void far *) 0;

    unsigned env_seg;

    

    printf("%04X    %04X    %04X (%6lu)   ", 

        FP_SEG(mcb), mcb->owner, mcb->size, (long) mcb->size << 4);



    if (IS_PSP(mcb))

    {

		void far *e = env(mcb);		/* MSC wants lvalue */

        if (env_seg = FP_SEG(e)) printf("%04X    ", env_seg);

        else                     printf("        ");

    

        display_progname(mcb);

    }

    

    if (! vect_2e) 

        vect_2e = GETVECT(0x2e);   /* do just once */

    if (! mcb->owner)

        printf("free ");

    /* 0008 is not really a PSP; belongs to CONFIG.SYS */

    else if (mcb->owner == 8)   

        printf("config ");

    /* INT 2Eh belongs to master COMMAND.COM (or other shell) */

    else if (belongs(vect_2e, FP_SEG(mcb), mcb->size))

        printf("%s ", getenv("COMSPEC"));   



    /* presence command line is independent of program name */

    if (IS_PSP(mcb))

        display_cmdline(mcb);

    display_vectors(mcb);

    printf("\n");

}



char far *env(MCB far *mcb)

{

    char far *e;

    unsigned env_mcb;

    unsigned env_owner;



    /*

        if the MCB owner is one more than the MCB segment then

            psp := MCB owner

            env_seg := make_far_pointer(psp, 2Ch)

            e := make_far_pointer(env_seg, 0)

        else

            return NULL

    */

    if (IS_PSP(mcb))

        e = MK_FP(ENV_FM_PSP(mcb->owner), 0);

    else 

        return (char far *) 0;

    

    /* 

       Does this environment really belong to this PSP? An

       environment is just another memory block, so its MCB is

       located in the preceding paragraph. Make sure the env

       MCB's owner is equal to the PSP whose environment this

       supposedly is! Thanks to Rob Adams of Phar Lap Software

       for pointing out the need for this check; this is a 

       good example of the sort of consistency check one must

       do when working with undocumented DOS.

    */

    env_mcb = MCB_FM_SEG(FP_SEG(e));

    env_owner = ((MCB far *) MK_FP(env_mcb, 0))->owner;

    return (env_owner == mcb->owner) ? e : (char far *) 0;

}



char far *progname_fm_psp(unsigned psp)

{

    char far *e;

    unsigned len;



    /* is there an environment? */

    if (! (e = env(MK_FP(MCB_FM_SEG(psp), 0))))

        return (char far *) 0;



    /* program name only available in DOS 3+ */

    if (_osmajor >= 3)

    {

        /* skip past environment variables */

        do e += (len = fstrlen(e)) + 1;

        while (len);



        /* 

            e now points to WORD containing number of strings following

            environment; check for reasonable value: signed because

            could be FFFFh; will normally be 1

        */

        if ((*((signed far *) e) >= 1) && (*((signed far *) e) < 10))

        {

            e += sizeof(signed);

            if (isalpha(*e))

                return e; /* could make canonical with INT 21h AH=60h */

        }

    }

    

    return (char far *) 0;

}



void display_progname(MCB far *mcb)

{

    char far *s;

    if (IS_PSP(mcb))

        if (s = progname_fm_psp((FP_SEG(mcb) + 1)))

            printf("%Fs ", s);

}



BOOL belongs(void far *vec, unsigned start, unsigned size)

{

    unsigned seg = FP_SEG(vec) + (FP_OFF(vec) >> 4); /* normalize */

    return (seg >= start) && (seg <= (start + size));

}



void display_cmdline(MCB far *mcb)

{

    /*

        psp := MCB owner

        cmdline_len := psp[80h]

        cmdline := psp[81h]

        print cmdline (display width := cmdline_len)

    */

    int len = *((BYTE far *) MK_FP(mcb->owner, 0x80));

    char far *cmdline = MK_FP(mcb->owner, 0x81);

    printf("%.*Fs ", len, cmdline);

}



void display_vectors(MCB far *mcb)

{

    static void far **vec = (void far **) 0;

    WORD vec_seg;

    int i;

    int did_one=0;

    

    if (! vec)

    {

        if (! (vec = calloc(256, sizeof(void far *))))

            fail("insufficient memory");

        for (i=0; i<256; i++)

            vec[i] = GETVECT(i);

    }

    

    for (i=0; i<256; i++)

        if (vec[i] && belongs(vec[i], FP_SEG(mcb), mcb->size))

        {

            if (! did_one) { did_one++; printf("["); }

            printf("%02X ", i);

            vec[i] = 0;

        }

    if (did_one) printf("]");

}



unsigned fstrlen(char far *s)

{

#if defined(_MSC_VER) && (_MSC_VER >= 600)

	return _fstrlen(s);

#else

    unsigned len = 0;

    while (*s++)

        len++;

    return len;

#endif	

}







mem2





/* 

MEM2.C -- walks DOS MCB chain(s): simple version

Andrew Schulman and Jim Kyle, July 1990

*/



#include <stdlib.h>

#include <stdio.h>

#include <dos.h>



typedef unsigned char BYTE;

typedef unsigned short WORD;

typedef unsigned long ULONG;

typedef void far *FP;



#ifndef MK_FP

#define MK_FP(seg,ofs)  ((FP)(((ULONG)(seg) << 16) | (ofs)))

#endif



#ifdef __TURBOC__

#define ASM asm

#else

#define ASM _asm

#endif



#pragma pack(1)



typedef struct {

    BYTE type;          /* 'M'=in chain; 'Z'=at end */

    WORD owner;         /* PSP of the owner */

    WORD size;          /* in 16-byte paragraphs */

    BYTE unused[3];

    BYTE dos4[8];

    } MCB;



void fail(char *s) { puts(s); exit(1); }



MCB far *get_mcb(void)

{

    ASM mov ah, 52h

    ASM int 21h

    ASM mov dx, es:[bx-2]

    ASM xor ax, ax

    /* in both Microsoft C and Turbo C, far* returned in DX:AX */

}



mcb_chk(MCB far *mcb)

{

    for (;;)

        if (mcb->type == 'M')

            mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);

        else

            return (mcb->type == 'Z');

}



void display(MCB far *mcb)

{

    char buf[80];

    sprintf(buf, "%04X    %04X    %04X (%6lu)", 

        FP_SEG(mcb), mcb->owner, mcb->size, (long) mcb->size << 4);

    if (! mcb->owner) 

        strcat(buf, "   free");

    puts(buf);

}



void walk(MCB far *mcb)

{

    printf("Seg     Owner   Size\n"); 

    for (;;)

        switch (mcb->type)

        {

            case 'M' : /* Mark : belongs to MCB chain */

                display(mcb);

                mcb = MK_FP(FP_SEG(mcb) + mcb->size + 1, 0);

                break;

            case 'Z' : /* Zbikowski : end of MCB chain */

                display(mcb);

                return;

            default :

                fail("error in MCB chain");

        }

}



#ifdef TRY_BUG

main(void)

{

    unsigned segm;

    ASM mov ah, 48h     /* Allocate Memory Block */

    ASM mov bx, 64h     /* get 100 paragraphs */

    ASM int 21h

    ASM jc done

    /* ax now holds initial segment of allocated block */

    ASM mov segm, ax

    printf("before: "); display(MK_FP(segm - 1, 0));



    ASM mov ax, segm

    ASM mov es, ax      /* now resize the block */

    ASM mov ah, 4Ah     /* Resize Memory Block */

    ASM mov bx, 0FFFFh  /* impossible (at least in real mode!) */

    ASM int 21h

    ASM jnc done        /* something seriously wrong if _didn't_ fail! */

    printf("after:  "); display(MK_FP(segm - 1, 0));

done:

    return 0;

}

#else

main(int argc, char *argv[])

{

    if (argc < 2)

        walk(get_mcb());            /* walk "normal" MCB chain */

    else

    {

        unsigned seg;

        sscanf(argv[1], "%04X", &seg);

        walk(MK_FP(seg, 0));       /* walk arbitrary MCB chain */

    }

    

    if (! mcb_chk(get_mcb()))

    {

        /* maybe do stack backtrace here, or dump registers */

        puts("Error in MCB chain - prepare for halt...");

        getchar();

    }

    else

        puts("MCB chain ok");

    

    return 0;

}

#endif


gods
Back to the "reversing gods" Lab

 


red

redhomepage red links red anonymity +ORC redstudents' essays redacademy database redbots wars
redantismut redtools redcocktails redjavascript wars redsearch_forms redmail_fravia
redIs reverse engineering illegal?