📄 tcwiz0.cpp
字号:
// File : TcWiz0.Cpp
// Implementation of the TcWizard class member functions.
// Continues in TcWiz1.Cpp
//
#include <dos.h>
#include <stdio.h>
#include <conio.h>
#include <assert.h>
#include "Disc.h"
#include "TcWizard.h"
#include "Disasm.h"
#include "Beautify.h"
#include "LibWiz.h"
char ArithOperators[][2] = {"","+","-","&","|","^"};
char CompOperators[][3] = {"> ",">=","< ","<=","==","!=","> ",">=","< ","<="};
char OppCompOperators[][3]={"<=","< ",">=","> ","!=","==","<=","< ",">=","> "};
TcWizard::TcWizard(Byte far *Ptr /* = 0 */,Dword size /* = 0 */)
{
SetCodePtr(Ptr,size);
StackTop = 0;
PendingTop = 0;
BlockTable = NULL;
NumBlocks = 0;
TracingFunctionCall=0;
}
TcWizard::~TcWizard()
{
FlushAll();
}
void TcWizard::FlushAll()
{
Flush();
if (BlockTable) free(BlockTable);
BlockTable=NULL;
NumBlocks=0;
LocalVars.Flush();
}
/*--------------------------------------------------------------
Flush - resets the object for another trial with the same
procedure. If we need to reset all info regarding the
procedure, call FlushAll.
--------------------------------------------------------------*/
void TcWizard::Flush()
{
for(int i=0;i<8+8;i++)
((char *)Regs[i])[0]=0;
for(i=0;i<NUM_STACK_LINES;i++)
{
((char *)Stack[i])[0]=0;
UseAsFnParms[i]=0;
}
StackTop=0;
((char *)CompareVar.Operand1)[0]=0;
for(i=0;i<NUM_PENDING_LINES;i++)
((char *)PendingLines[i])[0]=0;
PendingTop=0;
TracingFunctionCall=0;
}
void TcWizard::SaveState(TcWizardState &t)
{
int i;
for(i=0;i<8+8+4;i++)
{
if (Regs[i].IsEmpty()) t.Regs[i]=NULL;
else
{
t.Regs[i] = (char *)malloc(strlen((char *)Regs[i])+1);
if (t.Regs[i]==NULL)
{
sprintf(errorStr,"Insufficient memory to save internal state at %X",InstAddr);
ErrorList.Add(errorStr);
}
else strcpy(t.Regs[i],(char *)Regs[i]);
}
}
t.StackTop=StackTop;
t.PendingTop=PendingTop;
t.TracingFunctionCall=TracingFunctionCall;
t.InstAddr=InstAddr;
}
void TcWizard::RestoreState(TcWizardState &t)
{
for(int i=0;i<8+8+4;i++)
if (t.Regs[i]) strcpy((char *)Regs[i],t.Regs[i]);
StackTop=t.StackTop;
PendingTop=t.PendingTop;
TracingFunctionCall=t.TracingFunctionCall;
InstAddr=t.InstAddr;
}
void TcWizard::DestroyState(TcWizardState &t)
{
for(int i=0;i<8+8+4;i++) if (t.Regs[i]) free(t.Regs[i]);
}
void TcWizard::ClearPending()
{
PendingTop = 0;
}
/*
[-----------------------------------------------------------------------]
[ FlushPending ]
[-----------------------------------------------------------------------]
[ Stores the pending string into the passed parameter and returns if ]
[ any more strings are to be processed. ]
[-----------------------------------------------------------------------]
*/
int TcWizard::FlushPending(String &t,Word &iAddr)
{
if (!PendingTop) return 0;
int i = 0;
char *Pos1 = strchr((char *)PendingLines[i],';');
if (!Pos1) return 0;
char *Pos2 = strchr(Pos1 + 1,';');
assert(Pos2); // Make sure we have a matching pair of ';'.
int j=Pos2 - Pos1 + 1;
String tmp; tmp=Pos1;
((char *)tmp)[j] = 0; // Copy only the ";XXXX;" portion.
iAddr=atoi((char *)tmp+1); // Give the instruction address to the caller.
// Now delete the ";XXXX;" portion from the source String.
strcpy(Pos1,Pos2+1);
t = PendingLines[i];
PendingTop--;
for(i=0;i<PendingTop;i++) PendingLines[i]=PendingLines[i+1];
return 1;
}
int TcWizard::AddPending(char *str)
{
assert(PendingTop<=NUM_PENDING_LINES);
int pos = PendingTop;
PendingLines[PendingTop++] = str;
return pos;
}
/*
[-----------------------------------------------------------------------]
[ DeletePending ]
[-----------------------------------------------------------------------]
[ Deletes the pending line containing the string which is passed. ]
[ Useful in deleting entries for function calls, whose return values ]
[ have been used in subsequent instructions. ]
[-----------------------------------------------------------------------]
*/
void TcWizard::DeletePending(String &Key)
{
int i=0;
char *Pos1 = strchr((char *)Key,';');
if (!Pos1) return;
char *Pos2 = strchr(Pos1 + 1,';');
assert(Pos2); // Make sure we have a matching pair of ';'.
i=Pos2 - Pos1 + 1;
String tmp; tmp=Pos1;
((char *)tmp)[i] = 0; // Copy only the ";XXXX;" portion.
// Now delete the ";XXXX;" portion from the source String.
strcpy(Pos1,Pos2+1);
for(i=0;i<PendingTop;i++)
if (PendingLines[i].IsSubStrPresent(tmp,0))
break;
if (i<PendingTop)
{
for(;i<PendingTop;i++)
PendingLines[i] = PendingLines[i+1];
PendingTop--;
}
}
void TcWizard::SetCodePtr(Byte far *Ptr,Dword size)
{
CodePtr = Ptr;
Size = size;
Regs[REG_CS] = String((Word)FP_SEG(Ptr));
Regs[REG_ES] = String((Word)(FP_SEG(GetDataSegment())));
Regs[REG_DS] = String((Word)(FP_SEG(GetDataSegment())));
Regs[REG_SS] = Regs[REG_DS];
}
Byte far *TcWizard::GetMain()
{
Dword i;
Byte far *Ptr = CodePtr;
int n=0;
for(i=0;i<Size;i++)
{
if (*(Word far *)Ptr == 0x36FF) // Opcode for PUSH [mem].
{
Ptr += 4;
n++;
}
else if (*Ptr == 0x9a || *Ptr == 0xe8)
{
if (n>=3) break;
else Ptr++;
}
else { n=0; Ptr++; }
}
Word segment=0,offset=0;
if (n>=3)
{
if (*Ptr == 0x9a)
{
segment = *(Word far *)(Ptr+3);
offset = *(Word far *)(Ptr+1);
}
else
{
segment = FP_SEG(CodePtr);
offset = (Word)((Ptr - CodePtr) + 3 + (*(int far *)(Ptr + 1)));
}
}
return (Byte far *)MK_FP(segment,offset);
}
Byte far *TcWizard::GetDataSegment()
{
return (Byte far *)MK_FP(*(Word far *)(CodePtr+1),0);
}
Dword TcWizard::GetProcSize(Byte far *ProcBegin)
{
Disasm d;
return d.GetProcSize(ProcBegin);
}
void TcWizard::TranslateTrickyInsts(InstInfo &inst)
{
switch(inst.Instr)
{
case XOR : // XOR val,val==>MOV val,0
case OR : // OR val,val==>CMP val,0
if (inst.Operand1==inst.Operand2 &&
inst.Data11==inst.Data21 &&
inst.Data12==inst.Data22)
{
inst.Instr = (inst.Instr==XOR) ? MOV : CMP;
inst.Operand1 = inst.Operand1;
inst.Data11 = inst.Data11;
inst.Data21 = inst.Data21;
inst.Operand2 = IMMEDIATE;
inst.Data21 = 0;
inst.Data22 = 0;
}
break;
}
}
/*
[---------------------------------------------------------------------------]
[ SkipProcInit ]
[---------------------------------------------------------------------------]
[ Finds howmany 'PUSH's have been given in the beginning of the procedure ]
[ and subtracts an equal number of 'POP's at the end of the procedure ]
[ so that the stack is balanced properly. ]
[ The actual procedure size is stored and returned in the CodeSize variable.]
[ RETURN VALUE : No of bytes to skip at the beginning of the procedure. ]
[---------------------------------------------------------------------------]
*/
Dword TcWizard::SkipProcInit(Byte far *ProcBegin,Dword &ProcSize)
{
Disasm d;
Byte far *Inst = ProcBegin;
Dword ctr =0;
int InstLen = 0;
int InitOver=0;
int NumPushes=0;
// Skip the initial PUSH BP; MOV BP,SP; & any number of PUSHs following.
do
{
Inst += InstLen;
ctr += InstLen;
d.TraceInst(Inst,InstLen);
switch(d.CurInst.Instr)
{
case PUSH : NumPushes++; break; // Any number of pushes.
case MOV : if (!(d.CurInst.Operand1 == REG_DIRECT &&
d.CurInst.Data11 == REG_BP)) // Mov bp,sp
InitOver=1;
break;
case SUB : if (!(d.CurInst.Operand1 == REG_DIRECT &&
d.CurInst.Data11 == REG_SP)) // Sub sp,val
InitOver=1;
break;
default : InitOver=1;
}
}while(!InitOver);
int TotalPops=0;
// Find the total number of POPs after this initial code.
InstLen = 0;
InitOver=0;
do
{
Inst += InstLen;
d.TraceInst(Inst,InstLen);
switch(d.CurInst.Instr)
{
case POP : TotalPops++; break;
case RET : InitOver=1;
}
}while(!InitOver);
// Once again start from the beginning, till we reach the instruction
// from where No. of pops=No. of initial pushes, so that the actual
// procedure ends at that point.
InstLen = 0;
Inst = ProcBegin + ctr; // Skip the initial PUSHs and MOV BP,SP.
do
{
Inst += InstLen;
d.TraceInst(Inst,InstLen);
// Check if we have reached the MOV SP,BP instruction.
if (d.CurInst.Instr==MOV &&
(d.CurInst.Operand1==REG_DIRECT && d.CurInst.Data11==REG_SP) &&
(d.CurInst.Operand2==REG_DIRECT && d.CurInst.Data21==REG_BP))
// If so, this is the end of the procedure.
break;
if (d.CurInst.Instr==POP) TotalPops--;
}while(TotalPops>=NumPushes);
// Now we are in the first POP corresponding to the initial PUSHs.
ProcSize = Inst - (ProcBegin + ctr);
// Return the initial no. of bytes to skip.
return ctr;
}
int sortFunc(const void *a,const void *b)
{
if (((CBlock *)a)->Address > ((CBlock *)b)->Address) return 1;
if (((CBlock *)a)->Address < ((CBlock *)b)->Address) return -1;
return 0;
}
/*
[-----------------------------------------------------------------------]
[ IsSwitchStatement - Returns 1 if the given address corresponds to a ]
[ switch statement. Finds this out from the BlockTable array. This ]
[ array must be initialised before, by calling the Pass1 function. ]
[-----------------------------------------------------------------------]
*/
int TcWizard::IsSwitchStatement(Word Address)
{
for(int i=0;i<NumBlocks;i++)
if ((BlockTable[i].Type==C_SWITCH ||
BlockTable[i].Type==C_SWITCH_ORDERED) &&
BlockTable[i].Address==Address)
return BlockTable[i].Type;
return 0;
}
/*
[-----------------------------------------------------------------------]
[ Pass1 ]
[-----------------------------------------------------------------------]
[ Go thro' the procedure and find the addresses given for JMPs and put ]
[ in the BlockTable. ]
[ Also finds the library functions called in this procedure. ]
[ Also find the addresses of the SWITCH statements ]
[ Logic to find switch statements: ]
[ ---1st kind of switch.--- ]
[ switch(x) compiles as ]
[ MOV CX, NumSwitchEntries // excluding the DEFAULT Clause ]
[ MOV BX, AddressOfSwitchTable ]
[ [-- label1: ]
[ | CS: // or whatever segment it might be ]
[ | MOV Reg,[BX] ]
[ | CMP Reg,x ]
[ | [-- JZ label2 ]
[ | | ADD BX,2 ]
[ [--- LOOP label1 ]
[ | JMP AddressOf_DEFAULT_Clause ]
[ [-label2: ]
[ CS: // or whatever segment ]
[ JMP [BX+Disp] // Disp = size of the Values table in the ]
[ // Switch Table ]
[ // The address table starts at SwitchTable+Disp ]
[ ---2nd kind of switch.(Ordered-Switch)--- ]
[ switch(x) ]
[ { ]
[ case 0 : ]
[ case 1 : ]
[ case 2 : ]
[ ... ]
[ case MAX: ]
[ } compiles as shown below. ]
[ MOV Reg,x ]
[ CMP Reg,MAX ]
[ JA DefaultAddress ]
[ SHL Reg,1 ]
[ CS: ]
[ JMP [Reg+SwitchTableAddress] ]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -