⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcwiz0.cpp

📁 Decompilation Dos Program is a technique that allows you to recover lost source code. It is also nee
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//	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 + -