首页
社区
课程
招聘
7
一个themida加壳的程序LOADER 破解
发表于: 2006-11-24 15:06 14031

一个themida加壳的程序LOADER 破解

2006-11-24 15:06
14031

【文章标题】: 一个themida加壳的程序LOADER 破解
【文章作者】: rockhard
【作者邮箱】: wnh1@sohu.com
【软件名称】: test.exe
【加壳方式】: themida
【保护方式】: themida
【使用工具】: ollydbg,VC
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  遇到一个程序,在Ollydbg修改某些关键点可以运行了,但由于用THEMIDA加壳了,水平菜,脱不掉壳,每次只能在
  OLLYDBG中运行,想给他写个LOADER加载,然后修改内存。发现用CreateProcess 、ShellExecute和WinExec运行起来就报错,
  看来是加了LOADER的ANTI了。不能脱壳,只能在LOADER上做文章了。
  
  
  最直接的想法就是模拟explorer启动它,然后再修改。整个思路是这样:
  
  1、创建一个Event,用于进程间同步。
  2、将DLL注入到explorer中,
  3、Loader 调用WaitForObject进入等待状态。
  4、DLL 的DLL_PROCESS_ATTACH中创建一线程,用CreateProcess启动目标程序,这地方用CREATE_SUSPENDED标志,免得跑飞了
  5、DLL中用OpenEvent找到上面Event ,通知一次,激活LOADER线程。
  6、LOADER 查找目录程序,然后不断的SUSPEND目标进程,查看要修改的地方有没有已解码,如果已解码,PATCH,没有,将目标进程恢复运行一小段时间。
  
  源代码中没有什么注释,这儿帖出部分写上注释:
  
  PATCH代码段如下:
  //////////////////////////////////////////////////////////////////////////
  /**
    *  dwProcessID : Process ID which wanted to patch
    *
    *  return      : return TRUE if patch successfully ,otherwise return FALSE
    */
  
  #define PATCH_ADDRESS   0x401019      //目标进程中要PATCH 的地址
  #define PATCH_SIZE      16            //从目标进程中读取的字节数
  #define KEY_CODE        ("\x72\x12\x68\x3C\x60\x40\x00\x6A\x00\xFF\x15\xA0\x50\x40\x00\x33") //这个是壳解码后没有改动的程序代码
  #define NEW_CODE        ("\xEB\x12\x68\x3C\x60\x40\x00\x6A\x00\xFF\x15\xA0\x50\x40\x00\x33") //要修改后的代码
  #define TRY_TIMES       400  //只试搜索N次,如果还没出现,就不再查找了。
  
  
  BOOL CrackIt(DWORD dwProcessID)
  {
    BOOL bContinueRun=TRUE;
    BOOL bPatchSucess =FALSE;
    DWORD dwTryTimes=0;
    DWORD dwOldProtection,dwDummy;
  
    HANDLE hProcess =OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
    VirtualProtectEx (hProcess, (LPVOID)PATCH_ADDRESS, PATCH_SIZE,PAGE_EXECUTE_READWRITE, &dwOldProtection);
  
    //如果PATCH成功,设置bContinue为假,或尝试了N次后还不能找到要修改的代码,放弃了。
    while(bContinueRun && ++dwTryTimes<TRY_TIMES)
    {
      BYTE OldKeyCode[17];
  
      //让目标程序运行3ms 然后停下来,此时读目标程序的进程,查看是否已解码了
      SuspendResumeProcess(dwProcessID,FALSE);
      Sleep(3);
      SuspendResumeProcess(dwProcessID,TRUE);
  
      //读目标进程要PATCH地址处的数据
      ReadProcessMemory(hProcess, (LPVOID)PATCH_ADDRESS, OldKeyCode, PATCH_SIZE,&dwDummy);
  
      //判断是不是完全解码出来了
      if( !memcmp(OldKeyCode,(BYTE *)KEY_CODE, 16) ){
  
        //相同,说明已解码了,写入我们的新值
        WriteProcessMemory(hProcess, (LPVOID)PATCH_ADDRESS, NEW_CODE, PATCH_SIZE,&dwDummy);
        //we have patched ,stop check :-)
        bPatchSucess=TRUE;
        bContinueRun=false;
      }
    }
    VirtualProtectEx(hProcess, (LPVOID)PATCH_ADDRESS, PATCH_SIZE,dwOldProtection, &dwDummy);
  
    //for debug
    if(dwTryTimes >= TRY_TIMES)
      OutputDebugString("Cannot Match Code In Program !\n");
  
    //恢复目标程序执行
    SuspendResumeProcess(dwProcessID,FALSE);
  
    return bPatchSucess;
  
  }
  
  
  另外,在创建目标进程时不能写入绝对路径,不知道什么原因,后来通过SetCurrentDirectory改变工作目录解决了这个问题:
  #define WORK_DIRECTORY          "C:\\test"
  #define CRACK_PROGRAM_NAME      "test.exe"  //这地方如果写成c:\\test\\test.exe传给CreateProcess尽管目标程序运行,但explorer会出错.不明白
  
  DWORD WINAPI StartProcess(LPVOID lpParam)
  {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
  
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = TRUE;
  
    SetCurrentDirectory(WORK_DIRECTORY); //IMPORTANT!!
  
    BOOL bRet = CreateProcess(NULL, CRACK_PROGRAM_NAME,
      NULL, NULL, FALSE,  CREATE_SUSPENDED,
      NULL, NULL, &si,  &pi);
  
    if(bRet){
      CloseHandle (pi.hThread);
      CloseHandle (pi.hProcess);
    }
  
    HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,EVENT_OBJECT_NAME);
    SetEvent(hEvent);
  
    return 0;
  }
  
  注入到explorer的代码(感谢CSDN上的kesummer帮助):
  BOOL CInjector::InjectModuleInto(DWORD dwProcessId)
  {
    //不要给自己注入
    if(GetCurrentProcessId() == dwProcessId)
      return FALSE;
  
    //下面一段代码用于在explorer中查找dll是不是已经注入过了。
    BOOL bFound = FALSE;
    MODULEENTRY32 me32 = { 0 };
    me32.dwSize = sizeof(MODULEENTRY32);
  
    HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
    if(Module32First(hModuleSnap, &me32)) {
      do{
        if(lstrcmpiA(me32.szExePath, m_szDllName) == 0) {
          bFound = TRUE;
          break;
        }
      }
      while(Module32Next(hModuleSnap, &me32));
    }
    CloseHandle(hModuleSnap);
  
    if(bFound)  return FALSE;
  
  
    HANDLE hProcess = OpenProcess(
      PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION,
      FALSE, dwProcessId);
  
    if(hProcess == NULL) return FALSE;
  
   
  
    int cbSize = (strlen(m_szDllName) + 1);
    LPVOID lpRemoteDllName = VirtualAllocEx(hProcess, NULL, cbSize, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, lpRemoteDllName, m_szDllName, cbSize, NULL);
  
    HMODULE hModule=GetModuleHandle("kernel32.dll");
    LPTHREAD_START_ROUTINE pfnStartRoutine =
        (LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA");
  
    //用远程进程的LoadLibraryA函数的入口点做为远程线程的入口点,线程运行就相当于运行了LoadLibraryA
    HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartRoutine, lpRemoteDllName, 0, NULL);
    if(hRemoteThread == NULL)
    {
      CloseHandle(hProcess);
      return FALSE;
    }
  
    WaitForSingleObject(hRemoteThread, INFINITE);
  
    CloseHandle(hRemoteThread);
    CloseHandle(hProcess);
    m_dwProcessId=dwProcessId;
  
    return TRUE;
  }
  
  
  附件为全部源代码
  
--------------------------------------------------------------------------------
【经验总结】
  如果没有Loader检测,不需要注入到explorer了,直接用代码CreateProcess然后用上面的CrackIt函数就可以解决问题了。
  有检测只好找办法绕过去了。不知道有没有更简单的方法。
  
  本文是写给跟我一样菜鸟的,搞不定壳的,高手就别笑了。
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2006年11月24日 14:47:43


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
Youlor
为你点赞~
2023-10-21 00:01
伟叔叔
为你点赞~
2023-7-20 00:04
PLEBFE
为你点赞~
2023-5-18 01:49
心游尘世外
为你点赞~
2023-4-26 01:30
QinBeast
为你点赞~
2023-4-26 00:34
飘零丶
为你点赞~
2023-4-24 03:03
shinratensei
为你点赞~
2023-4-10 01:47
最新回复 (20)
雪    币: 340
活跃值: (957)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
2
themida写loader应该可以直接用CreateProcess的,你是不是加了DEBUG_ONLY_THIS_PROCESS?
2006-11-24 15:23
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
3
最初由 noword_forever 发布
themida写loader应该可以直接用CreateProcess的,你是不是加了DEBUG_ONLY_THIS_PROCESS?


不是themida的检测,这原程序中有检测。

用了几个办法都没办法加载起来,只好注入到explorer,让explorer启示录动它了。

注入explorer真是麻烦,不知道有没有更好的办法。
2006-11-24 15:34
0
雪    币: 215
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
野猪力量注入!!!
2006-11-24 19:16
0
雪    币: 331
活跃值: (56)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
5
野猪力量注入!!!
2006-11-24 19:25
0
雪    币: 277
活跃值: (312)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
6
野猪力量再注入!!!
2006-11-24 21:09
0
雪    币: 398
活跃值: (343)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
7
呵呵,完全不用这么麻烦D
不用0环,不用注入
只要稍微做些手脚,父进程就是Explorer了
2006-11-24 21:25
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
最初由 shoooo 发布
呵呵,完全不用这么麻烦D
不用0环,不用注入
只要稍微做些手脚,父进程就是Explorer了


我这就去找火柴棍把耳朵掏干净点,认真听指点,shoooo的每一行代码都闪耀着火花
2006-11-24 21:41
0
雪    币: 398
活跃值: (343)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
9
好像heXer曾经说过的
貌似对DEBUG方式的无效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <windows.h>
#include <tlhelp32.h>
#include <commdlg.h>
#pragma comment (lib, "comdlg32.lib")
#pragma comment (linker, "/filealign:0x200")
#pragma comment (linker, "/subsystem:windows")
#pragma comment (linker, "/entry:entry")
 
void AdjustPrivilege(int pid, BOOL bEnable)
{
    HANDLE    hProcess;
    HANDLE    hToken=0;
    TOKEN_PRIVILEGES tkp;
    tkp.PrivilegeCount = 1; 
    tkp.Privileges[0].Attributes = 0;
    if (bEnable)
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    if (LookupPrivilegeValue(NULL, "SeDebugPrivilege", &tkp.Privileges[0].Luid))
    {
        if (hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid))
        {
            if (OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken))
            {
                if (AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL))
                {
                    CloseHandle(hToken);
                }
            }
            CloseHandle(hProcess);
        }
    }
}
 
DWORD FindExplorer()
{
    HANDLE  hC;
    DWORD   i;
    BOOL    Next;
    char    szName[MAX_PATH];
 
    PROCESSENTRY32 p32 = {sizeof(p32)};
    hC = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,NULL);
    Next = Process32First(hC, &p32);
    i = 0;
    while (Next)
    {
        wsprintf(szName, "%s", p32.szExeFile);
        if (lstrcmpi(szName, "EXPLORER.EXE") == 0)
            return p32.th32ProcessID ;
        Next = Process32Next(hC, &p32);
        i++;
    }
    CloseHandle(hC);
    return 0;
}
 
HANDLE  hProcess;
DWORD   ZwCP;
DWORD   ZwCPEx;
DWORD   NoCP;
DWORD   NoCPEx;
 
 
void __declspec(naked) FuckZwCP()
{
    __asm
    {
        mov eax, hProcess
        mov [esp+0x10], eax
        mov eax, NoCP;
        push ZwCP;
        add dword ptr [esp], 5
        retn
    }
}
 
void __declspec(naked) FuckZwCPEx()
{
    __asm
    {
        mov eax, hProcess
        mov [esp+0x10], eax
        mov eax, NoCPEx;
        push ZwCPEx;
        add dword ptr [esp], 5
        retn
    }
}
 
void Patch()
{
    DWORD   odpt;
 
    ZwCP   = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwCreateProcess");
    ZwCPEx = (DWORD)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwCreateProcessEx");
    if (ZwCP != 0)
    {
        NoCP = *(LPDWORD)(ZwCP+1);
        VirtualProtect((LPVOID)ZwCP, 5, PAGE_EXECUTE_READWRITE, &odpt);
        *(LPBYTE)(ZwCP+0x00) = 0xE9;
        *(LPDWORD)(ZwCP+0x01) = (DWORD)FuckZwCP - ZwCP - 5;
    }
    if (ZwCPEx != 0)
    {
        NoCPEx = *(LPDWORD)(ZwCPEx+1);
        VirtualProtect((LPVOID)ZwCPEx, 5, PAGE_EXECUTE_READWRITE, &odpt);
        *(LPBYTE)(ZwCPEx+0x00) = 0xE9;
        *(LPDWORD)(ZwCPEx+0x01) = (DWORD)FuckZwCPEx - ZwCPEx - 5;
    }
}
 
void entry()
{
    AdjustPrivilege(GetCurrentProcessId(), TRUE);
    DWORD   Pid;
    Pid = FindExplorer();
    if (Pid == 0)
    {
        return ;
    }
    hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_PROCESS, FALSE, Pid);
    if (hProcess == NULL)
    {
        return ;
    }
    Patch();
 
    OPENFILENAME ofn = { sizeof(ofn) };
    char    szFilter[] = "EXE Files\0*.EXE\0\0";
    char    szFileName[MAX_PATH];
    char    szFilePath[MAX_PATH];
     
    ofn.hwndOwner = NULL;
    ofn.lpstrFile = szFileName;
    ofn.nFilterIndex = 1;
    ofn.lpstrFile[0] = 0;
    ofn.nMaxFile = MAX_PATH;
    ofn.lpstrTitle = "Loader";
    ofn.lpstrFilter = szFilter;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
    if (!GetOpenFileName(&ofn))
    {
        return ;
    }
    strcpy(szFilePath, szFileName);
    *(strrchr(szFilePath, '\\')+1) = 0;  //神奇,贴出来后两个反的变成一个了
 
    STARTUPINFO si = {sizeof(si)};
    PROCESS_INFORMATION pi = {0};
    CreateProcess(NULL, szFileName, NULL, NULL, FALSE, 0, NULL, szFilePath, &si, &pi);
    WaitForSingleObject(pi.hProcess, INFINITE);
    ExitProcess(0);
}
上传的附件:
2006-11-24 22:08
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
10
THX verrry much  shoooo,学习。。。
2006-11-24 23:09
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
11
试了一下,果然行。爽!
2006-11-24 23:11
0
雪    币: 898
活跃值: (4049)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
12
可以 SMC
2006-11-24 23:20
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
13
最初由 fly 发布
可以 SMC


这么说fly大侠还有其它办法.给点思路.
2006-11-24 23:24
0
雪    币: 898
活跃值: (4049)
能力值: ( LV9,RANK:3410 )
在线值:
发帖
回帖
粉丝
14
层层解码层层Patch就行了
原理都是一样的啊
2006-11-24 23:27
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
15
在网上找关于这方面资料时,
发现这个问题也是360给360安全卫士程序员志愿者出的问题:

http://blog.csdn.net/dedodong/archive/2006/10/07/1323925.aspx
2006-11-24 23:31
0
雪    币: 441
活跃值: (154)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
16
最初由 fly 发布
层层解码层层Patch就行了
原理都是一样的啊


对,这样也行,就是要多检查几处,多PATCH几个地方。不过要是被加壳程序有多种方法检测,改起来就有点麻烦了,一把他们得全找出来,然后再得修改。
2006-11-24 23:35
0
雪    币: 89
活跃值: (196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
猛人呀,
2006-11-25 10:02
0
雪    币: 214
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
18
强贴留名``
2006-11-26 14:50
0
雪    币: 255
活跃值: (207)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
19
期待脱壳机.
否则到处都是themida.
2006-11-26 15:16
0
雪    币: 255
活跃值: (207)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
20
期待脱壳机.
否则到处都是themida,连俺也顺手用上它了。
2006-11-26 15:16
0
雪    币: 224
活跃值: (147)
能力值: ( LV9,RANK:970 )
在线值:
发帖
回帖
粉丝
21
嘿嘿 好好研究下:)
2006-11-28 01:13
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册