【目 标】:终截者入侵阻止v5.26
【工 具】:W32Dasm中文版(GOLD)、OllyICE v1.10 修改版、EXESCOPE v6.30、LordPE v1.4,PEiD 0.94
【操作平台】:WindowsXP SP1
【作 者】: edisonH
【软件说明】:《终截者入侵阻止》 -- 100%拦截已知与未知病毒,可以有效拦截最新变种病毒及别有用心之人制作的“免杀病毒”;保护你所有的帐号与密码,是你的网上银行交易、游戏、聊天的保护专家!
【声 明】:本文为原创作品,转载请注明出处并保持文章的完整性, 谢谢!。
缘起:
看中终截者的驱动级注册表hook,找来一个最新版,安装后发现需要未注册版本只有30天试用期,且有以下不满之处,于是决定破解了并改造不满之处。
破解试用30天:
软件安装后,主程序启动正常,调节时间到30天后,使试用期过期,开启程序,出现过期对话框
破解开始:
按例,用PEiD先查壳,无壳。
1. 使用eXeScope打开主程序SecMain.exe,查找过期对话框,发现对话框ID为0x95
2. 使用W32Dasm打开主程序SecMain.exe,查找对话框ID为0x95的,在地址0x405740处发现
0040573D |. 8BF1 mov esi, ecx
0040573F |. 50 push eax
00405740 |. 68 95000000 push 95
00405745 |. 897424 14 mov [esp+14], esi
00405749 |. FF15 34144100 call [<&SkinWinLib.CSecBaseDlg::CSecBaseDlg>] ; 对话框创建
3. OllyICE载入主程序SecMain.exe,在地址0x405740处下断,运行,中断在0x405740处,回朔,发现过期检查处
00407D10 /$ 64:A1 0000000>mov eax, fs:[0]
00407D16 |. 6A FF push -1
00407D18 |. 68 EB064100 push 004106EB
00407D1D |. 50 push eax
00407D1E |. A1 5C7E4100 mov eax, [417E5C] ; 逝去的时间,只有软件刚打开时为0
00407D23 |. 64:8925 00000>mov fs:[0], esp
00407D2A |. 81EC 10030000 sub esp, 310
00407D30 |. 85C0 test eax, eax ; 是否刚打开
00407D32 |. 56 push esi
00407D33 |. 8B35 44104100 mov esi, [<&KERNEL32.GetTickCount>] ; kernel32.GetTickCount
00407D39 |. 57 push edi
00407D3A 74 1D je short 00407D59 ; 刚打开 则跳去 过期检查
00407D3C |. FFD6 call esi ; [GetTickCount
00407D3E |. 2B05 5C7E4100 sub eax, [417E5C] ; 上次检查到现在的时间差
00407D44 |. 8BF8 mov edi, eax
00407D46 |. FFD6 call esi ; [GetTickCount
00407D48 |. 81FF 00974901 cmp edi, 1499700 ; 比较时间差是否大于6小时
00407D4E |. A3 5C7E4100 mov [417E5C], eax ; 保存这次检查的时间
00407D53 0F82 5F010000 jb 00407EB8 ; 若距上次检查在6小时以内 则跳过 过期检查
00407D59 |> FFD6 call esi ; [GetTickCount
00407D5B |. A3 5C7E4100 mov [417E5C], eax
00407D60 |. E8 49510000 call <JMP.&MFC42.#1168_AFXGETMODULESTATE>
00407D65 |. 8B40 04 mov eax, [eax+4]
00407D68 |. 8B88 F0020000 mov ecx, [eax+2F0] ; 从安装到现在的时间差
00407D6E |. 83F9 1E cmp ecx, 1E ; 比较是否大于30天
00407D71 |. 7D 10 jge short 00407D83 ; 大于等于30天则跳
00407D73 |. B8 1E000000 mov eax, 1E
00407D78 |. 2BC1 sub eax, ecx
00407D7A |. 83F8 05 cmp eax, 5 ; 比较距过期是否大于5天
00407D7D |. 0F8D 35010000 jge 00407EB8 ; 大于等于5天则跳
00407D83 |> 8B35 907E4100 mov esi, [417E90]
......
00407DA9 |. E8 48730000 call <JMP.&MAINDLG.GETMAINDLG>
00407DAE |. 50 push eax
00407DAF |. 8D4C24 14 lea ecx, [esp+14]
00407DB3 |. E8 68D9FFFF call 00405720 ; 回朔到这里,往上看,发现过期检查处
{
00405720 /$ 6A FF push -1
00405722 |. 68 D0FF4000 push 0040FFD0 ; SE 处理程序安装
00405727 |. 64:A1 0000000>mov eax, fs:[0]
......
0040573D |. 8BF1 mov esi, ecx
0040573F |. 50 push eax
00405740 |. 68 95000000 push 95 ; 过期对话框ID0x95,这里下断,回朔回上一级调用
00405745 |. 897424 14 mov [esp+14], esi
00405749 |. FF15 34144100 call [<&SkinWinLib.CSecBaseDlg::CSecBaseDlg>] ; 创建对话框
......
004057F9 |. 64:890D 00000>mov fs:[0], ecx
00405800 |. 83C4 10 add esp, 10
00405803 \. C2 0400 retn 4
}
00407DB8 |. C68424 240300>mov byte ptr [esp+324], 1
......
00407EC1 |. 64:890D 00000>mov fs:[0], ecx
00407EC8 |. 81C4 1C030000 add esp, 31C
00407ECE \. C3 retn
4.可以看到,跳往00407EB8即可解除过期限制,这里有两处:
00407D53 0F82 5F010000 jb 00407EB8
和
00407D7D |. 0F8D 35010000 jge 00407EB8
所以这里的爆破方案有两种:
1.
00407D3A 74 1D je short 00407D59 ; 改为nop
00407D53 0F82 5F010000 jb 00407EB8 ; 改为jmp 00407EB8
2.
00407D71 |. 7D 10 jge short 00407D83 ; 改为nop
00407D7D |. 0F8D 35010000 jge 00407EB8 ; 改为jmp 00407EB8
另外,从上面的分析中可以看到,试用并没有真正的30天,而是25天
DIY改造:
不满之处:
终截者有主程序SecMain.exe及服务程序SecBkSrv.exe
1. 每次主程序SecMain.exe启动后,启动服务进程SecBkSrv.exe,并设置服务SecBkSrv为自动启动,下次系统重启时服务自动启动
2. 当关闭主程序后,服务没有关闭,继续占用资源
3. 服务进程SecBkSrv.exe启动后,在注册表Run项中添加 主程序SecMain.exe自启动项,下次重启后主程序自启动
计划:
1. 服务改为始终为手动方式,不会随重启自启动
2. 主程序退出时,关闭服务,节省资源
3. 主程序改为非强制自启动
详细步骤:
全部完成后,将修改SecMain.exe和SecBkSrv.exe,事先备份。
1. 服务改为始终为手动方式
OllyICE载入SecMain.exe,下断服务参数设置api函数ChangeServiceConfigA,回朔
00409265 |. 6A 03 push 2 ; |StartType参数 (2为自动,3为手动,改为push 3)
00409267 |. 68 A06A4100 push 00416AA0 ; ASCII "SecBkSrv"
0040926C |. E8 4F010000 call 004093C0 ; 回朔到这里
{
004093C0 /$ 55 push ebp
004093C1 |. 57 push edi
......
004093EB |. 53 push ebx
004093EC |. 56 push esi
.....
00409406 |. 8B4C24 18 mov ecx, [esp+18] ; |StartType启动类型,[esp+18]即为00409265处压入的参数push 3
0040940A |. 6A 00 push 0 ; /DisplayName = NULL
0040940C |. 6A 00 push 0 ; |Password = NULL
0040940E |. 6A 00 push 0 ; |ServiceStartName = NULL
00409410 |. 6A 00 push 0 ; |pDependencies = NULL
00409412 |. 6A 00 push 0 ; |pTagId = NULL
00409414 |. 6A 00 push 0 ; |LoadOrderGroup = NULL
00409416 |. 6A 00 push 0 ; |BinaryPathName = NULL
00409418 |. 6A FF push -1 ; |ErrorControl = SERVICE_NO_CHANGE
0040941A |. 51 push ecx ; |StartType
0040941B |. 68 10010000 push 110 ; |ServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS
00409420 |. 56 push esi ; |hService
00409421 |. FF15 2C104100 call [<&ADVAPI32.ChangeServiceConfigA>; 下断,回朔
......
0040949E \. C3 retn
}
2. 改造原程序,使其拥有关闭服务功能
先来看看,主程序怎么启动服务的
00408F00 /$ 6A FF push -1
00408F02 |. 68 C8074100 push 004107C8 ; SE 处理程序安装
......
00408F18 |. 68 3F000F00 push 0F003F
00408F1D |. 6A 00 push 0
00408F1F |. 6A 00 push 0
00408F21 |. FF15 1C104100 call [<&ADVAPI32.OpenSCManagerA>]; 第一步,打开服务控制管理器
00408F27 |. 8BD8 mov ebx, eax ; 得到服务控制管理器的句柄hSCManager,存于ebx中
......
00408F3E |> 8B4424 1C mov eax, [esp+1C]
00408F42 |. 6A 30 push 10
00408F44 |. 50 push eax
00408F45 |. 53 push ebx
00408F46 |. FF15 18104100 call [<&ADVAPI32.OpenServiceA>] ; 第二步,打开自己的服务SecBkSrv
00408F4C |. 8BF0 mov esi, eax ; 得到句柄hSecBkSrv,存于esi中
......
00408F6E |. 6A 00 push 0
00408F70 |. 6A 00 push 0
00408F72 |. 56 push esi ; hSecBkSrv
00408F73 |. FF15 00104100 call [<&ADVAPI32.StartServiceA>] ; 第三步,启动服务进程SecBkSrv.exe
......
00408FF0 \. C3 retn
再来看看,如果要关闭服务,要怎么做
call OpenSCManagerA 打开服务控制管理器
call OpenServiceA 打开服务
call ControlService 传递SERVICE_STOPED参数来关闭服务
看来,关闭服务和打开服务的第一第二步是一样的,为了减少增加的代码,改造一下上面主程序的打开服务的代码,增加关闭的功能。
(1) 先要修改打开服务时,设置的权限,改服务启动权限为 SERVICE_START | SERVICE_STOP,保证有结束权限
00408F42 |. 6A 10 push 10 ;SERVICE_START=0X10,SERVICE_STOP=0X20,改为push 30
00408F44 |. 50 push eax
00408F45 |. 53 push ebx
00408F46 |. FF15 18104100 call [<&ADVAPI32.OpenServiceA>]
(2) 用LordPE.EXE为程序添加了ADVAPI32.ControlService 输入函数
(3) 先看看ControlService函数
BOOL ControlService(
SC_HANDLE hService, // handle to service
DWORD dwControl, // control code
LPSERVICE_STATUS lpServiceStatus // pointer to service status structure
);
SERVICE_STATUS结构
typedef struct _SERVICE_STATUS { // 按注释赋值即可
DWORD dwServiceType; // 0
DWORD dwCurrentState; // 1 ,SERVICE_STOPED
DWORD dwControlsAccepted; // 0
DWORD dwWin32ExitCode; // -1
DWORD dwServiceSpecificExitCode; // 0
DWORD dwCheckPoint; // 0
DWORD dwWaitHint; // 0
} SERVICE_STATUS, *LPSERVICE_STATUS;
(4) 准备的差不多了,找个空的地方,打补丁增加关闭服务
补丁代码:
0x408f6e:
jmp 410e15
;修改为我的关闭服务函数
0x410e15:
mov eax,[esp+28]
cmp eax,12121212 ; 检查是否执行关闭服务的标记
je 410e2B
push 0
push 0
push esi
jmp 408f73 ; 不是关闭服务,跳回原函数
pushad
push 0 ; 在堆栈中压入SERVICE_STATUS结构
push 0
push 0
push -1
push 0
push 1
push 0
push esp ; &SERVICE_STATUS
push 1 ; SERVICE_STOPED
push esi ; hSecBkSrv服务句柄
call [42001e] ; ADVAPI32.ControlService
add esp,1c
popad
pop edi
pop ebp
pop esi
pop ebx
mov ecx,[esp+4]
mov fs:[0],ecx
add esp,10
ret
(5) 那么在哪里调用关闭服务的函数呢?
在主程序退出前,这里。
0040D46A |. 8945 98 mov [local.26], eax
0040D46D |. 50 push eax ; /status
0040D46E FF15 A4134100 call [<&MSVCRT.exit>] ; MSVCRT.exit
0x40d46e:
jmp 410e5b
nop
0x410e5b:
;调用关闭服务
pushad
mov eax,12121212 ; 自定义调用的标记
push eax
push 416aa0 ; "SecBkSrv"
call 408F00 ; 增加了关闭服务的函数入口
pop eax
pop eax
popad
call [4113A4] ; MSVCRT.exit
jmp 40d474
3. 改服务程序SecBkSrv.exe,使主程序改为非强制自启动
简单起见,只要改了SecBkSrv.exe中的字符串"SecMain.exe Hide"为一个目录中不存在的文件即可,这里我改为 no.exe
用W32Dasm在SecBkSrv.exe查找"SecMain.exe Hide",这里
00404776 |. BF 74AB4000 mov edi, 0040AB74 ; "SecMain.exe Hide"
0040AB74 53 65 63 4D 61 69 6E 2E 65 78 65 20 48 69 64 65 SecMain.exe Hide
改为
0040AB74 6E 6F 2E 65 78 65 00 00 00 00 00 00 00 00 00 00 no.exe..........
即可
修改好后,保存SecMain.exe和SecBkSrv.exe.
运行主程序SecMain.exe,退出
一切按照要求工作了,成功!
[课程]Android-CTF解题方法汇总!