//tcc script脚本编写例子------单步机
//目标程序来自某个视频教程的第一讲,是个加了UPX压缩壳的exe文件,可以试着加载下面的脚本代码,找到该程序的OEP
#include "D:\Tools\OllyICE\plugin\C_Script_Data\type.h"
//申明外部符号
extern HWND h_script_frame;//外部变量,使用前需要申明
extern void _stdcall Sleep(int);//外部函数,使用前必须申明
extern int _stdcall MessageBoxA(HWND,char*,char*,int);//同上
#define D_CALL_OFFSET_LIMIT 20//界定值,以此判断到底是远CALL还是近CALL
typedef unsigned long u_int32;
char *s_heap_str;//buffer,需要时存放字符串,实际上,后面并没有用上
char *s_heap_cmd;//buffer,需要时存放字符串,这个倒是用上了
#define tsa_abs(A) ((A)>0?(A):-(A))//求绝对值
void int3_insert(unsigned long u_addr)
{
_Setbreakpoint(u_addr,TY_ACTIVE,0);
}
void int3_remove(unsigned long u_addr)
{
_Deletebreakpoints(u_addr,u_addr+1,0);
}
void step_over()
{
_Go(0,0,STEP_OVER,1,1);
}
void step_in()
{
_Go(0,0,STEP_IN,1,1);
}
void run()
{
_Go(0,0,STEP_RUN,1,1);
}
void run_to(unsigned long u_addr)
{
_Tempbreakpoint(u_addr,TY_ONESHOT|TY_KEEPCOND); run();
}
void run_to_shortcut(unsigned long u_addr)
{
_Sendshortcut(PM_DISASM,u_addr,0x100,0,0,0x73);
}
int disasm_string(unsigned long u_addr,t_disasm *p_da)
{
char *s_cmd=(char*)malloc(128);
if(0==_Readcommand(u_addr,s_cmd))
{
free(s_cmd); return 0;
}
int i_byte=_Disasm(s_cmd,128,u_addr,0,p_da,DISASM_ALL,_Getcputhreadid());
free(s_cmd); return i_byte;
}
//先判断一条指令是不是跳转指令,然后再判断该指令是往前跳还是往后跳
//[往回跳,返回-1] [往前跳,返回1] [不是跳转指令,返回0]
int jump_type(unsigned long u_addr,t_disasm *p_dis)
{
unsigned long u_cmd_type=p_dis->cmdtype;
if((C_JMP==u_cmd_type) || ((C_JMC==u_cmd_type) && (1==p_dis->condition)))
{
unsigned long u_jmp_addr=p_dis->jmpaddr; if(u_jmp_addr>u_addr) return 1; return -1;
}
return 0;
}
//先判断一条指令是不是函数调用,然后再判断该指令近call还是远call
//[近call,返回-1] [远call,返回1] [非call,返回0]
int call_type(unsigned long u_addr,t_disasm *p_dis)
{
unsigned long u_cmd_type=p_dis->cmdtype;
unsigned long u_jmp_addr=p_dis->jmpaddr;
if(C_CAL==u_cmd_type)
{
if(tsa_abs(u_jmp_addr-u_addr)>D_CALL_OFFSET_LIMIT) return 1; return -1;
}
return 0;
}
//处理特殊情况
int extra_handle(unsigned long u_addr,t_disasm *p_dis)
{
if(0x5791E6==u_addr)//第一次跑飞的地址
{
run_to(0x5791EE); return 1;
}
else if(0x5791EF==u_addr)//第二次跑飞的地址
{
step_over(); return 1;
}
else if(0x47738C==u_addr)//OEP
{
MessageBoxA(h_script_frame,"到达OEP,请卸载脚本,以免影响调试","提示:",0); return 1;
}
return 0;
}
void on_code_insert()//当脚本被载入ollydbg进程的时候,on_code_insert将会被调用一次
{
s_heap_str=(char*)malloc(TEXTLEN);
s_heap_cmd=(char*)malloc(MAXCMDSIZE);
step_in();
}
void on_code_delete()//当脚本被卸载时,on_code_delete会被调用一次
{
free(s_heap_str);
free(s_heap_cmd);
}
//每当OD断下目标进程的时候,on_pausedex都会被调用(OD插件开发文档里是这么说的)
int on_pausedex(int reason,int dummy,t_reg *reg,DEBUG_EVENT *debugevent)
{
// Sleep(500);//让OD跑慢一点,便于观察,可以直接注释掉
u_int32 u_eip=reg->ip; t_disasm t_dis;
int i_cmd_len=disasm_string(u_eip,&t_dis);
if(0==i_cmd_len)
{
tsa_print(8,"无法解析当前指令,本次执行终止\n"); return 0;
}
if(extra_handle(u_eip,&t_dis)!=0) return 0;
if((-1)==jump_type(u_eip,&t_dis))
{
u_int32 u_next=u_eip+i_cmd_len;
tsa_print(11,"[eip:0x%0X]回跳,前往:0x%0X\n",u_eip,u_next);
run_to(u_next); return 0;
}
else if((-1)==call_type(u_eip,&t_dis))
{
tsa_print(17,"[eip:0x%0X]近CALL,步入\n",u_eip); step_in(); return 0;
}
step_over(); return 0;
}
--------------------------------------------------------------------------------------------------------------
2014/10/15
之前的界面有点太寒碜了,于是更新一下,网上找了一个封装DLL,支持一下语法高亮,就算是1.3版本吧
---------------------------------------------------------------------------------------------------------------
修正了一些问题。
还是把C_Script_Data和tcc_script.dll解压到OD的plugin目录。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)