远程线程注入时遇到的问题
注入技术--远程代码注入
注⼊技术--远程代码注⼊1.简介:代码注⼊和远程线程注⼊dll类似,但是隐蔽性更好,因为不产⽣⽂件.但是可靠性差,更加复杂代码注⼊时注⼊的代码部分是从本进程空间复制过去的,所以不能出现依赖于本进程的数据存在.所以注⼊的代码中数据,地址都是动态⽣成的, 因此可以考虑将这些数据作为参数传递给注⼊的代码.将代码和数据都注⼊到⽬标进程中(注意,该代码要以release模式编译才能运⾏成功,因为debug模式的编译的结构的函数调⽤是个jmp,⽽不是直接调⽤) //声明需要⽤到的函数typedef HMODULE(WINAPI *lpLoadLibraryA)(char* filename);typedef FARPROC(WINAPI *lpGetProcAddress)(HMODULE hModule, char* funcName);typedef int(WINAPI *lpMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);typedef struct _thread_param{lpLoadLibraryA loadFunc;lpGetProcAddress GetPFunc;char data[4][100]; //保存所有参数}thread_param;DWORD WINAPI threadProc(LPVOID param){thread_param* tparam = (thread_param*)param;HMODULE hd = tparam->loadFunc(tparam->data[0]); //data的第⼀个item是user32.dlllpMessageBoxA msg = (lpMessageBoxA)tparam->GetPFunc(hd, tparam->data[1]);//data的第2个参数是MessageBoxAmsg(0, tparam->data[2], tparam->data[3], 0);//data后2个参数是messagebox的参数}DWORD codeInject(DWORD pid){HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);if (hProcess==0||hProcess==INVALID_HANDLE_VALUE){return0;}thread_param param = { 0 };param.loadFunc = (lpLoadLibraryA)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");param.GetPFunc = (lpGetProcAddress)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress");memcpy(¶m.data[0], "user32.dll", 11);memcpy(¶m.data[1], "MessageBoxA", 12);memcpy(¶m.data[2], "freesec", 8);memcpy(¶m.data[3], "inject", 7);DWORD codesize = (DWORD)codeInject - (DWORD)threadProc; //计算线程函数的代码⼤⼩LPVOID database = VirtualAllocEx(hProcess, 0, sizeof(thread_param), MEM_COMMIT, PAGE_READWRITE);DWORD written;HANDLE hThread;if (database==0){CloseHandle(hProcess);return0;}WriteProcessMemory(hProcess, database, ¶m, sizeof(thread_param), &written);LPVOID codebase = VirtualAllocEx(hProcess, 0, codesize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);if (codebase == 0){VirtualFreeEx(hProcess, database, sizeof(thread_param), MEM_FREE);CloseHandle(hProcess);return0;}WriteProcessMemory(hProcess, codebase, threadProc, codesize, &written);if ((hThread=CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)codebase, database, 0, 0))!=0){VirtualFreeEx(hProcess, database, sizeof(thread_param), MEM_FREE);VirtualFreeEx(hProcess, codebase, codesize, MEM_FREE);CloseHandle(hThread);CloseHandle(hProcess);return1;}VirtualFreeEx(hProcess, database, sizeof(thread_param), MEM_FREE);VirtualFreeEx(hProcess, codebase, codesize, MEM_FREE);CloseHandle(hProcess);return0;}。
远程线程注入
远程线程注⼊原理: 打开⽬标进程以后,将要注⼊的动态库的路径写⼊这个地址空间,然后调⽤开启远程线程的函数,来执⾏LoadLibraryA或者LoadLibraryW(其实不存在LoadLibrary这个函数,他只是⼀个宏,如果是UNICODE环境的话会调⽤LoadLibraryW,否则就是LoadLibraryA)来执⾏这个动态库,动态库⼀旦被加载起来,DllMain中的DLL_PROCESS_ATTACH则会被执⾏,我们将要执⾏的代码写在DLL_PROCESS_ATTACH分⽀即可。
之所以把LoadLibraryA(W)作为线程函数,是因为它刚好只有1个参数,在不考虑参数类型的情况下,可以认为它的原型与线程函数⼀样,⽰例如下:HMODULE WINAPI LoadLibraryW(_In_ LPCWSTR lpLibFileName);DWORD WINAPI ThreadProc(_In_ LPVOID lpParameter); 注意:由于从Windows Vista 开始,微软为了增强系统的安全性,对系统服务和登录⽤户进⾏了会话(Session)隔离,系统服务属于会话0,登录的第⼀个⽤户属于会话1,之前系统服务和第⼀个登录⽤户都属于会话0。
此⽅法并不能突破SESSION 0隔离。
原因是在CreateRemoteThread 函数中对此进⾏了检查,如果不在同⼀会话中,调⽤ CsrClientCallServer 为新进程进⾏登记的操作就会失败,这就直接导致了线程创建的失败。
步骤:1. 打开⽬标进程2. 在⽬标进程中申请空间3. 将要注⼊的Dll路径写⼊刚申请的空间中4. 获取LoadLibrary函数地址5. 在⽬标进程中创建线程,线程回调函数就是LoadLibrary函数,回调函数参数就是要注⼊的Dll路径6. 等待线程结束7. 清理环境代码如下:BOOL CBiaoBai1Dlg::CreateRemoteThreadInjectDll(DWORD dwProcessId, char* pszDllFileName){// 1.打开⽬标进程HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, // 打开权限FALSE, // 是否继承dwProcessId); // 进程PIDif (NULL == hProcess){MessageBox("打开⽬标进程失败!");return FALSE;}// 2.在⽬标进程中申请空间LPVOID lpPathAddr = VirtualAllocEx(hProcess, // ⽬标进程句柄0, // 指定申请地址strlen(pszDllFileName) + 1, // 申请空间⼤⼩MEM_RESERVE | MEM_COMMIT, // 内存的状态PAGE_READWRITE); // 内存属性if (NULL == lpPathAddr){MessageBox("在⽬标进程中申请空间失败!");CloseHandle(hProcess);return FALSE;}// 3.在⽬标进程中写⼊Dll路径SIZE_T dwWriteSize = 0;if (FALSE == WriteProcessMemory(hProcess, // ⽬标进程句柄lpPathAddr, // ⽬标进程地址pszDllFileName, // 写⼊的缓冲区strlen(pszDllFileName) + 1, // 缓冲区⼤⼩&dwWriteSize)) // 实际写⼊⼤⼩{MessageBox("⽬标进程中写⼊Dll路径失败!");CloseHandle(hProcess);return FALSE;}//获取LoadLibraryA的函数地址//FARPROC可以⾃适应32位与64位FARPROC pFuncProcAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (NULL == pFuncProcAddr){MessageBox("获取LoadLibrary函数地址失败!");CloseHandle(hProcess);return FALSE;}// 4.在⽬标进程中创建线程HANDLE hThread = CreateRemoteThread(hProcess, // ⽬标进程句柄NULL, // 安全属性NULL, // 栈⼤⼩(PTHREAD_START_ROUTINE)pFuncProcAddr, // 回调函数lpPathAddr, // 回调函数参数NULL, // 标志NULL // 线程ID);if (NULL == hThread){MessageBox("⽬标进程中创建线程失败!");CloseHandle(hProcess);return FALSE;}// 5.等待线程结束WaitForSingleObject(hThread, -1);DWORD code;GetExitCodeThread(hThread, &code);code = GetLastError();// 6.清理环境VirtualFreeEx(hProcess, lpPathAddr, 0, MEM_RELEASE);CloseHandle(hThread);CloseHandle(hProcess);return TRUE;}。
.Net常见线程安全问题整理
.Net常见线程安全问题整理最近线上⼜出现了⼏次线程安全问题导致的服务异常,线程安全问题都是隐藏的炸弹,有可能⼏个⽉都不出问题,也有可能连续⼏天爆炸好⼏次,问题出现的结果完全是⽆法确定的,包括但不限于如下结果:1. 应⽤异常,且⽆法⾃恢复,必须重启站点或服务;2. 陷⼊死循环,导致CPU占⽤100%,从⽽整台服务器崩溃;3. 错误数据⼊库,导致⼀系列的排查、数据修复的困难,甚⾄可能⽆法修复数据;因此,很有必要做⼏次全局的筛查,做⼀些特征值搜索和处理,简单梳理了⼀下,凡是符合如下5种特征的代码,都有线程不安全的可能性:1、类的静态变量:public class Iamclass{static Dictionary<string, string> _cache = new Dictionary<string, string>();public static void Operation(){_cache.Add(new Guid().ToString(), "1");// 线程不安全代码}}2、类的静态属性:public class Iamclass{static Dictionary<string, string> Cache {get; set;} = new Dictionary<string, string>();public static void Operation(){Cache.Add(new Guid().ToString(), "1");// 线程不安全代码}}3、单例对象的静态变量:public class XxxService{IIamclass instance = IocHelper.GetSingleInstance<IIamclass>(); // 获取单例}public class Iamclass : IIamclass{Dictionary<string, string> _cache = new Dictionary<string, string>();public void Operation(){_cache.Add(new Guid().ToString(), "1");// 线程不安全代码}}4、单例对象的静态属性:public class XxxService{IIamclass instance = IocHelper.GetSingleInstance<IIamclass>(); // 获取单例}public class Iamclass : IIamclass{Dictionary<string, string> Cache {get; set;} = new Dictionary<string, string>();public void Operation(){Cache.Add(new Guid().ToString(), "1");// 线程不安全代码}}5、多线程共享的局部变量public class XxxService{public void Operation(){var cache = new Dictionary<string, string>();System.Threading.Tasks.Parallel.For(1, 10, idx =>{cache.Add(new Guid().ToString(), "1"); //线程不安全代码});}}列举下处理过的⼏次线程安全问题,都是如下2类问题:1、应⽤错误且⽆法恢复的,通常异常为:索引超出了数组界限:public class MessageService : BaseService{private static Dictionary<string, Timer> _timerDict = new Dictionary<string, Timer>();public async void SendMessageAsync(string msgId, MessageInputDto2 input){var timer = new Timer(60 * 1000) { AutoReset = true };_timerDict[msgId] = timer; // 问题代码timer.Elapsed += (sender, eventArgs) =>{try{/* 具体业务代码 */timer.Stop();timer.Close();_timerDict.Remove(msgId);}catch(Exception exp){// 异常处理代码}}}}解决⽅法,⼀般是加锁注:如果加lock 可能出现瓶颈,要进⾏流程梳理,是否要更换实现⽅案:lock(_timerDict){_timerDict[msgId] = timer; // 问题代码}timer.Elapsed += (sender, eventArgs) =>{try{/* 具体业务代码 */timer.Stop();timer.Close();lock(_timerDict){_timerDict.Remove(msgId);}}catch(Exception exp){// 异常处理代码}}2、陷⼊死循环,导致服务器CPU 100%卡顿问题:有个常见业务,获取⼀串没有使⽤过的随机数或随机字符串,⽐如⽤户⾝份Token,⽐如抽奖等等下⾯是常见的获取不重复的随机数代码,在_rnd.Next 没有加锁,其内部⽅法InternalSample会导致返回结果都是0,从⽽导致while陷⼊死循环:public class CodeService{private static Random _rnd = new Random(Guid.NewGuid().GetHashCode());public static GetCode(){var ret = "";var redis = IocHelper.GetSingleInstance<IRedis>();// 获取⼀个未使⽤过的序号do{ret = _rnd.Next(10000).ToString(); // 问题代码}while(!redis.Add(ret, "", TimeSpan.FromSeconds(3600)));return ret;}}解决⽅法,双重校验:加锁,并判断循环次数:public class CodeService{private static Random _rnd = new Random(Guid.NewGuid().GetHashCode());public static GetCode(){var ret = "";var redis = IocHelper.GetSingleInstance<IRedis>();var maxLoop = 10;// 获取⼀个未使⽤过的序号do{lock(_rnd){ret = _rnd.Next(10000).ToString();}}while(!redis.Add(ret, "", TimeSpan.FromSeconds(3600)) && (maxLoop--) > 0); if(maxLoop <= 0){throw new Exception("10次循环,未找到可⽤数据:" + ret);}return ret;}}https:///youbl/article/details/101693752 转载。
远程过程调用失败0x800706be
远程过程调⽤失败0x800706be今天⽤数据库突然发⽣了《远程过程调⽤失败0x800706be》,参考⼀下⽹站解决今天在配置SqlServer启动参数时,发现"开始菜单"->“配置⼯具”->“SQL Server 配置管理器”中的“SQL Server 服务”⼀项,右边栏⾥显⽰的是“远程过程调⽤失败[0x800706be]”。
经过仔细分析,发现这是由于我安装VS2012时附带安装了更⾼版本的“SQL Server服务”所导致的。
该错误只需要卸载Microsoft SQL Server 2012 的LocalDB服务即可。
这是出现的问题:该问题是由于,我在安装VS2012时,附带安装了Microsoft SQL Server 2012 (Express)Local Data 服务,现阶段公司所使⽤的Microsoft SQL Server数据库是SQL Server2008。
所以果断在“控制⾯板”->"程序"->“程序和功能”->“Microsoft SQL Server 2012 (Express)Local Data ”->卸载.这是问题解决⽅案:在卸载完成后,要想看到效果,我们需要关闭当前的“SQL Server 配置管理器”,重新在"开始菜单"->“配置⼯具”->“SQL Server 配置管理器”中点击打开“配置管理器”。
这时我们就可以看到问题已经解决了。
卸载掉 Microsoft SQL Server 2012 Express LocalDB;或 Microsoft SQL Server 2012 LocalDB;注意卸载所有的版本,如2014和2016。
线程池注意事项和常见问题
线程池注意事项和常见问题线程池是一种常用的多线程编程技术,它可以提高程序的性能和稳定性。
但是,在使用线程池时,我们也需要注意一些问题和常见错误。
本文将介绍线程池注意事项和常见问题,帮助读者更好地使用线程池。
一、线程池注意事项1.线程池大小的选择线程池大小的选择需要根据实际情况进行调整。
如果线程池过小,可能会导致任务无法及时处理,从而影响程序的性能;如果线程池过大,可能会导致系统资源的浪费,从而影响程序的稳定性。
2.任务队列的选择任务队列的选择也需要根据实际情况进行调整。
如果任务队列过小,可能会导致任务无法及时处理,从而影响程序的性能;如果任务队列过大,可能会导致系统资源的浪费,从而影响程序的稳定性。
3.线程池的关闭线程池的关闭需要注意线程池中的任务是否已经全部完成。
如果线程池中还有未完成的任务,直接关闭线程池可能会导致任务丢失或者程序异常。
因此,在关闭线程池之前,需要等待所有任务都已经完成。
二、线程池常见问题1.线程池中的任务出现异常线程池中的任务出现异常可能会导致整个线程池崩溃。
因此,在编写任务时,需要注意异常处理,避免出现未处理的异常。
2.线程池中的任务阻塞线程池中的任务阻塞可能会导致线程池无法及时处理其他任务,从而影响程序的性能。
因此,在编写任务时,需要注意任务的执行时间,避免出现长时间阻塞的情况。
3.线程池中的任务过多线程池中的任务过多可能会导致系统资源的浪费,从而影响程序的稳定性。
因此,在使用线程池时,需要根据实际情况进行调整,避免出现任务过多的情况。
4.线程池中的线程过多线程池中的线程过多可能会导致系统资源的浪费,从而影响程序的稳定性。
因此,在使用线程池时,需要根据实际情况进行调整,避免出现线程过多的情况。
总之,线程池是一种常用的多线程编程技术,但是,在使用线程池时,我们也需要注意一些问题和常见错误。
只有正确地使用线程池,才能提高程序的性能和稳定性。
木马注入远程进程
个我多个 d ( u 动志 链接库)文件。 自从
来,动志链接库一直是其基础.Wid ws no AI P 中的所有函数都包含在D L 。 个最 L中 3
重要的DL 是Ken 3 .l、 s r2 dl L r d 2 dl U e3 .l 和
I tl Al De] 合键 .也就看不到该程 Mirs f 公司推出 Wid ws 作系统以 C r+ t + 1 组 c oo t no 操
步骤 :
( 用 F n d W d 1 ) i in O W 和
lSa t d es/ 线程开始执行的地址 p trAd rs, / L V D lP rmee , / 向传给 P OI p aa tr/ 指 线程函数的变量
维普资讯
木 马注入远程进程
李银兵’ 闰敬
I 唐 山 学院 计算 中 0  ̄ 0 6 00 2 .唐 山 师范 学 院计 算机 科 学 系 0 5 0 5O0
干个线 程 ,线 程是操 作系统 分配处 理器
时间的 基本单 位 ,一个线程 是一个 执行
I2 rl i 。Ken l2 d 包含用于管理内 re3 .l l X /0 0 P 2 0 的任务管理器.Wid ws X / n o P GD 3 .l 20 的任务管理器均能轻 世显示 出木 马进 存, 00 进程 和线程的各个函数I s r2 山l e 3 . 包 U
含用于执行用 户界面任务 ( 如宙 口的创建 和消总. 的传送 ) 的各个函数, DI2叫 包 G 3. 现在 有很 多木马程 序 .有的 术马是 使用进 程注入技 术实现 隐藏 ,进程注 入 含用于画 图和 显示文本 的各个函数 DLL由多个功能 函数构 成,它不能 恶意 的 ,盗窃 用 户的关 键 信息和 材 料 , 技术是将 自己的代码嵌八到正运行的进程 n o 中不同进程间的地 拽立运行 , 一 般都是 由其它 进程加 载并 甚至给 用户带来经济上的损失。大部分木 的技 术。在 Wi d ws L 文件不能独立运行.所 马在进程查看器 中看不到 ,所以查杀木马 址空阃是 隔离的 ,每 个进程 都有 自己的 调用的 因为 D L L ,假设有 不太容 易,其 中进程的隐藏是木马比较关 私有内 存地址 空间 ,一 个进 程无法 访问 以在进程列表中井不会出现 D L 个木 马DL 通过 别的进程来运行它 . 1, 那 键的技术。奉文探 讨了木马的隐 藏技术, 另一个进 程的 内存地址 空间 ,如果 要编 使读者掌握木马隐藏的原理 .从而使读者 写能够 与其他进 程进行 通信 的程序 ,或 么无论是入侵检测软 件还是进程 列表 中. 可以 用时发现木马并将其清除 ,有效地保 者能够对其他进程进行操作的应用程序将 都 只会 出现宿 主进程 而并不 会出现木 马 例如 要困难得 多。 但仍有 多种方 法可以打 破 DLL,如果高 主进 程是可信 进程 ( 护 自己的资料和信息 。 X L RE E E , L 进程 的界 限 ,访问 另一个进 程的地址 空 E P O R. X ) 那 幺木马DL 作 为宿
远程线程注入的检测与卸载方法研究
远程线程注入DLL的检测与卸载方法研究摘要研究了Windows操作系统下的一种木马检测技术,该木马结合了远程线程注入、动态链接库(DLL)等技术。
针对目前最新的远程线程注入实现木马隐藏的关键技术,提出了一种进程被远程注入动态链接库的检测方法和相应动态链接库的卸载方法。
实验表明,这种方法对已被远程线程注入DLL的进程检测和恢复效果明显。
关键词远程线程注入进程模块DLL1引言在Windows系统中,每个进程都有自己的私有地址空间,进程不能创建属于另外一个进程的内存指针,而远程线程技术正是通过特殊的内核编程手段,打破进程的界限来访问另一个进程的地址空间,以达到对自身进行隐藏的目的[1]。
远程线程注入DLL技术是指非法程序利用在进程中创建远程线程的方法,进入到该进程的内存空间,并通过已有进程在其内存空间中加载启动DLL程序[2]。
由于DLL文件没有程序逻辑,不能独立运行,只能通过进程加载并调用才能启动,所以在进程列表中不会出现DLL文件。
因此,如果非法程序以DLL的形式存在,并通过其他进程进行加载,即可实现的非法程序的隐藏。
由于DLL文件是寄生在其它进程中的,一般的进程管理工具无法列举出DLL文件,所以通过远程线程注入DLL的方法将木马注入到其它进程是一种很好的木马病毒隐藏方法[3]。
为了防止远程线程注入,文献[4]等在远程线程注入木马的攻防研究中提出设置钩子Creat—eRemoteThread()函数的方法来防止非法线程的注入。
该方法能够在一定程度上防止远程线程注人,但钩子技术存在一些固有的弊端,例如,增加了系统对每个消息的处理使系统变慢;木马制造者可以自己反挂钩CreateRemoteThread()函数,绕过系统钩子,从而达到远程线程注入的目。
显然,使用挂钩CreateRemoteThread()函数的技术,不能绝对杜绝远程线程的注入。
本文提出一种新的检测进程方法,该方法可以有效的检测出已被远程线程注入到进程中的可疑模块,并加以卸载。
线程阻塞的原因有哪些
线程阻塞的原因有哪些线程阻塞是指一个线程无法继续执行下去的状态,它可以由多种原因引起。
下面是一些常见的线程阻塞的原因:1.等待输入/输出:当一个线程从外部获取输入或者向外部发送输出时,如果输入/输出操作比较耗时,那么线程将会被阻塞,直到输入/输出操作完成。
2. 睡眠状态:线程可以通过调用`Thread.sleep(`方法来进入睡眠状态,这会使线程在指定的时间内暂停执行。
在这段时间内,线程被阻塞,并且不会占用CPU资源。
3.等待其他线程完成:当一个线程调用另一个线程的`join(`方法时,它将会等待被调用线程执行完毕,然后再继续执行。
如果被调用线程还没有执行完毕,调用线程将会被阻塞。
4.等待锁释放:当一个线程尝试获取一个被其他线程持有的锁时,它将会被阻塞,直到获得锁的线程释放锁。
5.等待条件满足:线程可以通过调用`wait(`方法来等待一些条件满足。
当条件不满足时,线程将会被阻塞。
直到其他线程调用该对象的`notify(`或`notifyAll(`方法,通知等待线程可以继续执行。
6.等待资源可用:当线程尝试获得系统资源,但是系统资源已经被其他线程占用时,线程将会被阻塞,直到资源变得可用。
7.等待信号量:当线程尝试获取一个信号量时,如果信号量的资源已经被其他线程占用完毕,那么线程将会被阻塞,直到有其他线程释放信号量。
8.等待网络连接建立:当一个线程尝试与其他进程或者远程服务建立网络连接时,如果连接过程比较耗时,线程将会被阻塞。
9.等待锁资源:当一个线程尝试获取一个锁资源时,如果锁已经被其他线程占用,那么线程将会被阻塞,直到其他线程释放该锁。
10.等待用户输入:当一个线程等待用户输入时,线程将会被阻塞,直到用户输入完毕。
总结来说,线程阻塞的原因可以归结为以下几个方面:输入/输出操作、睡眠状态、等待其他线程完成、等待锁释放、等待条件满足、等待资源可用、等待信号量、等待网络连接建立、等待锁资源、等待用户输入等。
记一次paramiko远程连接遇到的坑
记⼀次paramiko远程连接遇到的坑背景:⼯作中遇到了⼀个问题,需要⽤到windows向windows连接(⽂件传发)以及,linux向windows连接(⽂件传发)的需求。
⾃然⽽然会考虑到⽤paramiko,然⽽paramiko我⽤的⽐较多的还是连接linux的操作,⾄于连接windows的操作没⽤过。
在⽹上搜索⼀段时间后,发现⽹上的教程基本上没有。
折腾⼀段时间后发现了winrm,winrm在命令发送⽐较简单,但是⽂件上传、下载,还是没有合适的路⼦(或者说适合⾃⼰的⽅法)。
⼀番折腾后还是想⾃⼰研究⼀把paramiko。
问题1:在⽹上搜索⽅法的时候,发现别⼈可以直接⽤paramiko连接windows,并⽤psutil 获取cpu、内存等数据,代码和我们连接linux基本⼀样的,那么我也来试⼀下:import paramikoclient=paramiko.SSHClient()client.set_missing_host_key_policy(paramiko.AutoAddPolicy())client.connect(hostname='***',port=22,username='Administrator',password='***')client.close()思考1:也可能是因为windows不⽀持ssh连接,那么我就试⼀下transaport:scp=paramiko.Transport((IP,22))scp.connect(username=username,password=password)sftp=paramiko.SFTPClient.from_transport(scp)scp.close()依然遇到了同样的问题思考2:既然别⼈可以,代码应该就没有问题,那么会是什么问题。
⽹上搜索⼀番,发现可能和openssh有关系,接着下载openssh思考3:会不会因为是22 端⼝没有开启导致的,于是乎查看端⼝情况发现端⼝是开的思考4:会不会是因为防⽕墙的原因,关闭防⽕墙之后发现还是同样的问题,此时的⼼态已经接近崩溃问题3:即使我们⽬标端的windows的机器安装了openssh但是我们还是不能连接上去:思考5:继续尝试后发现我的⽬标windows的机器可以通过ssh连接到其他的机器上⾯,但是我却不能ssh到⽬标机器上⾯,这时候似乎明⽩了什么。
ASP.NETCore新建线程中使用依赖注入的问题
Core新建线程中使⽤依赖注⼊的问题问题来⾃博问的⼀个提问。
TCPService 通过构造函数注⼊了 ContentService , ContentService 的实例依赖了 AppDbContext (继承⾃ EF Core 的 DbContext)。
在TCPService 中通过 Thread.Start 启动了⼀个新的线程执⾏了 TCPService 中的 Receive ⽅法,在 Receive ⽅法中通过 ContentService 进⾏保存数据库的操作,⽽在访问 AppDbContext 的实例时出现对象已被 Disposed 的错误。
Object name: 'AppDbContext'. --->System.ObjectDisposedException: Cannot access a disposed object. A common cause ofthis error is disposing a context that was resolved from dependency injection and then later trying to use the same contextinstance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care ofdisposing context instances.针对这个问题,尝试改为通过构造函数注⼊ IServiceProvider ,在 TCPService.Receive (在新线程中执⾏的⽅法)中通过 IServiceScope 解析using (var scope = _serviceProvider.CreateScope()){var contentService = scope.ServiceProvider.GetRequiredService<ContentService>();//...}结果发现 IServiceProvider 也被 DisposedSystem.ObjectDisposedException: Cannot access a disposed object.Object name: 'IServiceProvider'.由此可以推断在 Core 中在新建的线程中⽆法通过依赖注⼊的⽅式访问实现了 IDisposable 接⼝的对象(单例对象除外,但实现 IDisposable 接⼝的类型通常不会注册为单例),也就是只要请求⼀结束,实现 IDisposable 接⼝的对象的 Dispose ⽅法就会被调⽤。
远程线程注入木马的攻防研究
其 中, 钩子 服务 器用 于在 合适 时机 把驱 动注入 其 它进 程 , 它也 可 以 管理 驱 动 , 可 以从 注 入点 获 还 取 驱 动 的活 动 情况 ; 动就 是 一 个 D L 主 要 实现 驱 L,
替换 指 定 函数 CetR m t hed ) 自定 义 函 ra e oe ra ( 的 e T 数 的代 码 , 该 函数进 行拦 截 。 对
实施 自己的破坏 作用 , 盗取 密码 。 如 基 于这 样 的一 种 原 理 : 态嵌 入 技 术 使 用 Cet 动 ra . e e oe hed )函数 在 其 它 进 程 中 创 建 远 程 线 R m t ra ( T 程 , 创建 的远程 线程 可 以共享 远 程进程 的地址 空 被
这种新型木马 的拦截 。测试结果表 明, 这种拦截技术对远程线程注入式木 马的拦 截是有效的。 关键词
中图 分 类 号 T 3 3 0 P9 .8
1 引 言
特 洛伊木马是 指 表面 上是 有 用 的软 件 、 际 目 实 的却是危害计算 机安全并 导致严重破 坏 的计算机 程
序 。木马 的一 个 重要 特点 就 是 隐身 。通 常 , 马程 木 序 经常采用一 种伪 装方 法 欺骗 用户 , 以达 到藏 身 的 目的。隐藏技术 一直是木 马设 计人员 研究 的重要 技
一
( 被调 用 , 转 入 到所 注入 的 D L中执行 自定 义 ) 就 L 函数 。从 而使 得木 马无法 注入 , 法 隐藏 。 无
本文 中 , 现对 木 马远 程注入 函数 的拦 截框 架 实
如 图 1所示 。
方 面 , 进入 到 了 目标 进 程 的地 址 空 间 , 能 够 它 才 在上述 文献 中提到 的动态嵌 入 技术 , 际上是 实
windows:shellcode远程线程hook注入(四)
windows:shellcode远程线程hook注⼊(四)⾸先是个table,table⾥⾯装满了各个回调函数的⼊⼝;其次:既然是kernelcallback,应该是被内核回调的,那么内核在什么时候才会回调这些函数了?众说周知,windows操作系统的基⽯就是⽆数个展现在⽤户界⾯的窗⼝(所以该操作系统才得名windows的嘛),窗⼝之间是需要互相通信的,窗⼝和系统其他模块之间也是要互相通信的, table⾥的这些函数通常⽤于窗⼝响应各种不同类型的消息。
例如,A窗⼝给B窗⼝发送WM_COPYDATA消息,B 窗⼝就会执⾏_fnCOPYDATA函数(shellcode注⼊关键点就在这了:在⽬标进程写⼊shellcode,然后让_fnCOPYDATA指向shellcode的⼊⼝);⽽当⼀个键盘消息来了,收到消息的窗⼝就会执⾏__ClientImmProcessKey;kernelcallbacktable在哪了?既然⽬标进程选explorer,就从这⾥开始逐个查看(1)先看看explorer的各种数据,发现peb在008e1000这⾥;kd> !process 0 0 explorer.exePROCESS ffff9006c6645080SessionId: 1 Cid: 09cc Peb: 008e1000 ParentCid: 09b4DirBase: 48555000 ObjectTable: ffffb789d5512040 HandleCount: 3177.Image: explorer.exe(2)继续查看PEB的内容:在偏移0x58处找到exlporer进程的内核回调表:kd> dt _PEB 008e1000nt!_PEB+0x000 InheritedAddressSpace : 0 ''+0x001 ReadImageFileExecOptions : 0 ''+0x002 BeingDebugged : 0 ''+0x003 BitField : 0x4 '' ................................................+0x054 Padding1 : [4] ""+0x058 KernelCallbackTable : 0x00007ffa`ef0e31e0 Void(3)继续查看这个表的内容:根据上⾯回调函数表的地址继续查表内函数地址,如下:kd> dps 00007ffa`ef0e31e000007ffa`ef0e31e0 00007ffa`ef07e3e000007ffa`ef0e31e8 00007ffa`ef0da99000007ffa`ef0e31f0 00007ffa`ef08199000007ffa`ef0e31f8 00007ffa`ef086a9000007ffa`ef0e3200 00007ffa`ef0860b000007ffa`ef0e3208 00007ffa`ef0daf0000007ffa`ef0e3210 00007ffa`ef08745000007ffa`ef0e3218 00007ffa`ef0dad2000007ffa`ef0e3220 00007ffa`ef0db1b000007ffa`ef0e3228 00007ffa`ef0dadd000007ffa`ef0e3230 00007ffa`ef083e4000007ffa`ef0e3238 00007ffa`ef0dae2000007ffa`ef0e3240 00007ffa`ef088b3000007ffa`ef0e3248 00007ffa`ef0db35000007ffa`ef0e3250 00007ffa`ef0db35000007ffa`ef0e3258 00007ffa`ef08eb50 (4)查看第⼀个函数,也就是_fnCOPYDATA代码如下:kd> u 00007ffa`ef07e3e000007ffa`ef07e3e0 4883ec58 sub rsp,58h00007ffa`ef07e3e4 33c0 xor eax,eax00007ffa`ef07e3e6 4c8bd1 mov r10,rcx00007ffa`ef07e3e9 89442438 mov dword ptr [rsp+38h],eax00007ffa`ef07e3ed 4889442440 mov qword ptr [rsp+40h],rax00007ffa`ef07e3f2 394108 cmp dword ptr [rcx+8],eax00007ffa`ef07e3f5 740b je 00007ffa`ef07e40200007ffa`ef07e3f7 48394120 cmp qword ptr [rcx+20h],rax(5)只要把这个函数的内容换成我们⾃⼰的shellcode就⾏,代码下⾯会贴出来,这⾥先下个断点:kd> bp 00007ffa`ef07e3e0(6)执⾏代码,成功断了下来:kd> gBreakpoint 0 hit0033:00007ffa`ef07e3e0 4883ec58 sub rsp,58hkd> k# Child-SP RetAddr Call Site00 00000000`056ff398 00007ff8`bbbc3b14 0x00007ffa`ef07e3e001 00000000`056ff3a0 00000000`00000000 0x00007ff8`bbbc3b14 F5放过去继续执⾏,成功弹出了记事本: (7)KernelCallBackTable如下,全是内核回调函数:typedef struct _KERNELCALLBACKTABLE_T {ULONG_PTR __fnCOPYDATA;ULONG_PTR __fnCOPYGLOBALDATA;ULONG_PTR __fnDWORD;ULONG_PTR __fnNCDESTROY;ULONG_PTR __fnDWORDOPTINLPMSG;ULONG_PTR __fnINOUTDRAG;ULONG_PTR __fnGETTEXTLENGTHS;ULONG_PTR __fnINCNTOUTSTRING;ULONG_PTR __fnPOUTLPINT;ULONG_PTR __fnINLPCOMPAREITEMSTRUCT;ULONG_PTR __fnINLPCREATESTRUCT;ULONG_PTR __fnINLPDELETEITEMSTRUCT;ULONG_PTR __fnINLPDRAWITEMSTRUCT;ULONG_PTR __fnPOPTINLPUINT;ULONG_PTR __fnPOPTINLPUINT2;ULONG_PTR __fnINLPMDICREATESTRUCT;ULONG_PTR __fnINOUTLPMEASUREITEMSTRUCT;ULONG_PTR __fnINLPWINDOWPOS;ULONG_PTR __fnINOUTLPPOINT5;ULONG_PTR __fnINOUTLPSCROLLINFO;ULONG_PTR __fnINOUTLPRECT;ULONG_PTR __fnINOUTNCCALCSIZE;ULONG_PTR __fnINOUTLPPOINT5_;ULONG_PTR __fnINPAINTCLIPBRD;ULONG_PTR __fnINSIZECLIPBRD;ULONG_PTR __fnINDESTROYCLIPBRD;ULONG_PTR __fnINSTRING;ULONG_PTR __fnINSTRINGNULL;ULONG_PTR __fnINDEVICECHANGE;ULONG_PTR __fnPOWERBROADCAST;ULONG_PTR __fnINLPUAHDRAWMENU;ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD;ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD_;ULONG_PTR __fnOUTDWORDINDWORD;ULONG_PTR __fnOUTLPRECT;ULONG_PTR __fnOUTSTRING;ULONG_PTR __fnPOPTINLPUINT3;ULONG_PTR __fnPOUTLPINT2;ULONG_PTR __fnSENTDDEMSG;ULONG_PTR __fnINOUTSTYLECHANGE;ULONG_PTR __fnHkINDWORD;ULONG_PTR __fnHkINLPCBTACTIVATESTRUCT;ULONG_PTR __fnHkINLPCBTCREATESTRUCT;ULONG_PTR __fnHkINLPDEBUGHOOKSTRUCT;ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX;ULONG_PTR __fnHkINLPKBDLLHOOKSTRUCT;ULONG_PTR __fnHkINLPMSLLHOOKSTRUCT;ULONG_PTR __fnHkINLPMSG;ULONG_PTR __fnHkINLPRECT;ULONG_PTR __fnHkOPTINLPEVENTMSG;ULONG_PTR __xxxClientCallDelegateThread;ULONG_PTR __ClientCallDummyCallback;ULONG_PTR __fnKEYBOARDCORRECTIONCALLOUT; ULONG_PTR __fnOUTLPCOMBOBOXINFO;ULONG_PTR __fnINLPCOMPAREITEMSTRUCT2;ULONG_PTR __xxxClientCallDevCallbackCapture;ULONG_PTR __xxxClientCallDitThread;ULONG_PTR __xxxClientEnableMMCSS;ULONG_PTR __xxxClientUpdateDpi;ULONG_PTR __xxxClientExpandStringW;ULONG_PTR __ClientCopyDDEIn1;ULONG_PTR __ClientCopyDDEIn2;ULONG_PTR __ClientCopyDDEOut1;ULONG_PTR __ClientCopyDDEOut2;ULONG_PTR __ClientCopyImage;ULONG_PTR __ClientEventCallback;ULONG_PTR __ClientFindMnemChar;ULONG_PTR __ClientFreeDDEHandle;ULONG_PTR __ClientFreeLibrary;ULONG_PTR __ClientGetCharsetInfo;ULONG_PTR __ClientGetDDEFlags;ULONG_PTR __ClientGetDDEHookData;ULONG_PTR __ClientGetListboxString;ULONG_PTR __ClientGetMessageMPH;ULONG_PTR __ClientLoadImage;ULONG_PTR __ClientLoadLibrary;ULONG_PTR __ClientLoadMenu;ULONG_PTR __ClientLoadLocalT1Fonts;ULONG_PTR __ClientPSMTextOut;ULONG_PTR __ClientLpkDrawTextEx;ULONG_PTR __ClientExtTextOutW;ULONG_PTR __ClientGetTextExtentPointW;ULONG_PTR __ClientCharToWchar;ULONG_PTR __ClientAddFontResourceW;ULONG_PTR __ClientThreadSetup;ULONG_PTR __ClientDeliverUserApc;ULONG_PTR __ClientNoMemoryPopup;ULONG_PTR __ClientMonitorEnumProc;ULONG_PTR __ClientCallWinEventProc;ULONG_PTR __ClientWaitMessageExMPH;ULONG_PTR __ClientWOWGetProcModule;ULONG_PTR __ClientWOWTask16SchedNotify;ULONG_PTR __ClientImmLoadLayout;ULONG_PTR __ClientImmProcessKey;ULONG_PTR __fnIMECONTROL;ULONG_PTR __fnINWPARAMDBCSCHAR;ULONG_PTR __fnGETTEXTLENGTHS2;ULONG_PTR __fnINLPKDRAWSWITCHWND;ULONG_PTR __ClientLoadStringW;ULONG_PTR __ClientLoadOLE;ULONG_PTR __ClientRegisterDragDrop;ULONG_PTR __ClientRevokeDragDrop;ULONG_PTR __fnINOUTMENUGETOBJECT;ULONG_PTR __ClientPrinterThunk;ULONG_PTR __fnOUTLPCOMBOBOXINFO2;ULONG_PTR __fnOUTLPSCROLLBARINFO;ULONG_PTR __fnINLPUAHDRAWMENU2;ULONG_PTR __fnINLPUAHDRAWMENUITEM;ULONG_PTR __fnINLPUAHDRAWMENU3;ULONG_PTR __fnINOUTLPUAHMEASUREMENUITEM; ULONG_PTR __fnINLPUAHDRAWMENU4;ULONG_PTR __fnOUTLPTITLEBARINFOEX;ULONG_PTR __fnTOUCH;ULONG_PTR __fnGESTURE;ULONG_PTR __fnPOPTINLPUINT4;ULONG_PTR __fnPOPTINLPUINT5;ULONG_PTR __xxxClientCallDefaultInputHandler;ULONG_PTR __fnEMPTY;ULONG_PTR __ClientRimDevCallback;ULONG_PTR __xxxClientCallMinTouchHitTestingCallback; ULONG_PTR __ClientCallLocalMouseHooks;ULONG_PTR __xxxClientBroadcastThemeChange;ULONG_PTR __xxxClientCallDevCallbackSimple;ULONG_PTR __xxxClientAllocWindowClassExtraBytes; ULONG_PTR __xxxClientFreeWindowClassExtraBytes;ULONG_PTR __fnGETWINDOWDATA;ULONG_PTR __fnINOUTSTYLECHANGE2;ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX2;} KERNELCALLBACKTABLE;。
解决多线程中11个常见问题
并发危险解决多线程代码中的11 个常见的问题Joe Duffy本文将介绍以下内容:▪基本并发概念▪并发问题和抑制措施▪实现安全性的模式▪横切概念本文使用了以下技术:多线程、.NET Framework目录数据争用忘记同步粒度错误读写撕裂无锁定重新排序重新进入死锁锁保护戳记两步舞曲优先级反转实现安全性的模式不变性纯度隔离并发现象无处不在。
服务器端程序长久以来都必须负责处理基本并发编程模型,而随着多核处理器的日益普及,客户端程序也将需要执行一些任务。
随着并发操作的不断增加,有关确保安全的问题也浮现出来。
也就是说,在面对大量逻辑并发操作和不断变化的物理硬件并行性程度时,程序必须继续保持同样级别的稳定性和可靠性。
与对应的顺序代码相比,正确设计的并发代码还必须遵循一些额外的规则。
对内存的读写以及对共享资源的访问必须使用同步机制进行管制,以防发生冲突。
另外,通常有必要对线程进行协调以协同完成某项工作。
这些附加要求所产生的直接结果是,可以从根本上确保线程始终保持一致并且保证其顺利向前推进。
同步和协调对时间的依赖性很强,这就导致了它们具有不确定性,难于进行预测和测试。
这些属性之所以让人觉得有些困难,只是因为人们的思路还未转变过来。
没有可供学习的专门API,也没有可进行复制和粘贴的代码段。
实际上的确有一组基础概念需要您学习和适应。
很可能随着时间的推移某些语言和库会隐藏一些概念,但如果您现在就开始执行并发操作,则不会遇到这种情况。
本文将介绍需要注意的一些较为常见的挑战,并针对您在软件中如何运用它们给出一些建议。
首先我将讨论在并发程序中经常会出错的一类问题。
我把它们称为“安全隐患”,因为它们很容易发现并且后果通常比较严重。
这些危险会导致您的程序因崩溃或内存问题而中断。
当从多个线程并发访问数据时会发生数据争用(或竞争条件)。
特别是,在一个或多个线程写入一段数据的同时,如果有一个或多个线程也在读取这段数据,则会发生这种情况。
【DELPHI】利用远程线程注入DLL
【DELPHI】利⽤远程线程注⼊DLLSDK⽂档⾥是这样描述的:进程是⼀个正在运⾏的程序,它拥有⾃⼰的地址空间,拥有⾃⼰的代码,数据和其他系统资源.⼀个进程包含了⼀个或者多个运⾏在此进程内的线程. 从定义上看出进程⼀定要有线程,线程是进程内存中的独⽴实体. 线程插⼊技术就是把⼀个线程弄到别的进程中执⾏的技术。
远程线程插⼊代码之DLL注⼊技术:我们先编写个简单的DLL:library TestDll;usesWindows;{$R *.res}procedure func_a;beginMessageBox(0,'I love delphi','Function form Tset DLL',0);end;procedure func_b(MSG:pchar);beginMessageBox(0,MSG,'Function form Tset DLL',0);end;beginfunc_a;func_b('I like it too!');end.我们弄个程序加载它的⼊⼝点,> 新建⼀个普通程 >加⼀个按钮> 按钮事件只要写⼀句 >loadlibrary('testdll.dll'); > 存为MainShow.dpr运⾏,单击按钮,怎么养弹出东西了吧。
DLL会写了,现在的问题就是怎么注⼊了我们⽬的只是让对⽅的程序运⾏⼀句loadlibrary('testdll.dll');⽽已你可能要问,既然刚才说了远程线程可以直接注⼊⼀个线程,为什么还要多此⼀举反过来再调⽤DLL呢这是因为,远程线程技术⼀般是直接对⽬标程序的内存进⾏操作,我们知道不同程序的虚拟内存是不⼀样的,所以很多函数的地址不⼀定⼀样,⽽程序运⾏的时候实际上是Call函数地址进⾏函数调⽤的;⽽DLL调⽤时其实是被映射到进程内存⾥⾯,DLL拥有⾃⼰的导⼊表,资源,函数等东西,实际上就是⼀个完整的程序,映⼊内存后和执⾏⼀个程序效果是⼀样的这样我们就不⽤考虑那些乱七⼋糟的东西,只要安⼼的写功能即可.我们看看WindowsAPI CreateThread :function CreateThread(lpThreadAttributes: Pointer; //安全指针⼀般nil就可以了dwStackSize: DWORD; //线程初始化尺⼨,⼀般⽤0,获得与主线程⼀样尺⼨(不够⾃⼰会增加,别担⼼)lpStartAddress: TFNThreadStartRoutine; //⼀个指向要执⾏线程函数的指针,这个函数必须遵守stdcall约定,并且可带⼀个参数,参数必须是指针类型lpParameter: Pointer; //函数的参数dwCreationFlags: DWORD;//控制创建标志,⽤0表⽰线程⽴刻执⾏var lpThreadId: DWORD) //返回标识变量我觉得没什么⽤,反正句柄都有了): THandle; //返回线程的句柄stdcall;//标准调⽤ Windows下API⼀般都是标准调⽤看起来似乎⽐较复杂,等下举个例⼦我们把DLL源码⾥⾯的func_b拷到刚才那个EXE上稍微修改下procedure func_b(MSG:pchar); stdcall;beginMessageBox(0,MSG,'Function form Tset DLL',0);sleep(10000);//线程暂停N久(不超过10s)end;加上2个按钮第⼀个procedure TForm1.Button2Click(Sender: TObject);beginfunc_b('123');end;第⼆个procedure TForm1.Button3Click(Sender: TObject);var tid:longword;//放返回值,不放她不让执⾏,郁闷str:pchar;//便于获得pointerbeginstr:='123';createthread(nil,0,@func_b, //函数名前⾯加@是得到函数指针pointer(str),//虽然str也是指针,但是delphi就是要pointer型的,那就转⼀下类型0 , tid);//tid纯属放着占格式的,⼀般我们⽤不到end;//上⾯CreateThread看得懂吧,⼏乎都是默认设置,以后套下去⽤就是了实际上都是调⽤func_b,只是第⼆个过程⽤了信新线程但是效果是不⼀样的第⼀个按钮按下弹出窗⼝后,程序卡死了(暂停10000)第⼆个却不会为什么呢我们可以这样理解窗⼝看做⼀个主线程,执⾏func_b,弹出窗⼝,然后主线程挂起,于是卡死了⽽第⼆个过程创建⼀个新线程,新线程执⾏func_b,弹出窗⼝,挂起10000,但是由于主线程没有挂起,所以看起来关掉窗⼝后没什么事情发⽣(实际上那个线程还在偷偷执⾏,直到线程代码运⾏完,只是它卡死不会影响你)这个如果明⽩了那么下⾯就容易理解了看看这个函数function CreateRemoteThread(hProcess: THandle;lpThreadAttributes: Pointer;dwStackSize: DWORD;lpStartAddress: TFNThreadStartRoutine;lpParameter: Pointer;dwCreationFlags: DWORD;var lpThreadId: DWORD): THandle; stdcall;除了函数名不⼀样,下⾯的参数多了个hProcess: THandle;,剩下的完全⼀样呵呵,这个东西就是本节课的关键了先看函数名就知道是⼲什么⽤的了 '创建远程线程'⽤法和刚才基本⼀致就是hProcess: THandle是什么呢这⾥要填的是被注⼊线进程的句柄什么是句柄打个⽐⽅,对象是⼀个门,句柄就是那个把⼿,通过句柄我们可以对门进⾏操作也就是说我们利⽤句柄来操作某些东西(包括进程,线程等等)你有没有注意到,CreateThread和CreateRemoteThread都返回⼀个THandle,也就是线程的句柄还有loadlibrary也会返回DLL的句柄,我们可以利⽤他们对相关对象进⾏操作那么怎么获得进程句柄呢⼀般采⽤先得到进程PID再⽤下⾯的函数取得句柄function OpenProcess(dwDesiredAccess: DWORD; //访问标志⼀般填写 PROCESS_ALL_ACCESS,这样这个句柄可以获得最⼤操作权限bInheritHandle: BOOL;//可否继承,这个跟⼦程序有关,⽆所谓了,填false和true都可以,反正我们⾃⼰能操作就可以dwProcessId: DWORD): //要获得句柄的进程IDTHandle; stdcall;//返回句柄有时候会返回0,说明打开句柄失败了⼀般是你的权限不够(⽐如你想对Winlogon这些系统级程序操作)这时候我们需要提升权限⼀般Debug权限就可以了(其实操作权限⾥⾯最⾼了)提升的过程我写好了直接调⽤就可以了(修改进程令牌到Debug级别,为什么这样写这⾥不详细讲了,⾃⼰去⽹上搜索下) procedure GetDebugPrivs;varhToken: THandle;tkp: TTokenPrivileges;retval: dword;beginIf (OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken)) thenbeginLookupPrivilegeValue(nil, 'SeDebugPrivilege' , tkp.Privileges[0].Luid);tkp.PrivilegeCount := 1;tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;AdjustTokenPrivileges(hToken, False, tkp, 0, nil, retval);end;end;不会晕吧应该记得我刚才提到了要PID,那怎么得到呢⼀般⽤FindWindow和GetWindowThreadProcessId配合的到这样写先var Pid:longword;//储存那个PIDGetWindowThreadProcessId(FindWindow('Notepad', nil), @PID);这样就找到笔记本的PID,再如'Shell_TrayWnd'可以找到Explorer的窗⼝类名据说可以⽤SPY++查询,不过这东西我没见过,呵呵当然还可以枚举进程判断进程名等等这个先告⼀段落.好了,拿Windows的笔记本下⼿吧procedure TmyForm.Button4Click(Sender: TObject);var h:longword;//PID和THandle 的类型其实都是longword,改个名字⽽已,所以可以通⽤beginwinexec('notepad',1);//运⾏笔记本GetWindowThreadProcessId(FindWindow('notepad', nil), @h);//得到Pid存在hh:=OpenProcess(PROCESS_ALL_ACCESS, False, h);//得到handle存在h,后⾯那个是变量pid,算完放到前⾯的h是句柄(两个不同的东西,只是类型⼀样⽽已)sleep(2000);//等2秒TerminateProcess(h,0);//关闭笔记本,h是那个句柄,0表⽰正常退出end;运⾏起来就是打开⼀个笔记本,⼤约2s后关掉它不知道⼤家看懂了没有,没有不要紧,只是为了证明我们可以拿到⼀个可操作的进程句柄好像万事具备了吧那试试远程线程了吧再建⼀个按钮前⾯的还是这样写,再把那个建⽴线程的拷过来改成CreateRemoteThread加上h参数procedure TmyForm.Button5Click(Sender: TObject);varh:longword;tid:longword;str:pchar;beginstr:='123';winexec('notepad',1);GetWindowThreadProcessId(FindWindow('notepad', nil), @h);h:=OpenProcess(PROCESS_ALL_ACCESS, False, h);CreateRemoteThread(h,nil, 0, @func_b, pointer(str), 0 , tid);end;运⾏起来笔记本出来了,对话框也出来了...可是对话框却不是我们弄的那个,是个报错的看看写了什么内存'0x00000000'不能为'writen'为什么呢记得我刚才说的么远程线程是在别的程序⾥运⾏⼀个线程相当于让⾥⼀个函数执⾏CreateThread所以,函数的地址不⼀定是⼀样的,更何况笔记本⾥⾯怎么可能会有func_b这个我们⾃⼰写的函数呢这么⼀来当然要出错了这下傻了,那怎么注⼊我们要的函数呢记得我们要讲什么吗 -利⽤远程线程进⾏DLL注⼊我们可以把函数写在DLL⾥⾯,⽤远程线程让⽬标进程加载它这样函数就执⾏了我们只要想办法让对⽅程序loadlibrary('testdll.dll');那就OK了看看LoadLibrary的原型function LoadLibrary(lpLibFileName: PAnsiChar): HMODULE; stdcall;你应该发现了它和线程要求的函数格式⼏乎⼀样参数是指针型PAnsiChar就是pchar,⼀个指向字符串的指针返回HMODULE,HMODULE实质是longword(改个名字⽽已)^_^,那就远程运⾏它吧这时候你可能会想,LoadLibrary的地址要怎么得到呢要知道,LoadLibrary是⼀个API(在Kernel32.dll⾥⾯),实际上,每个Win32程序都需要⾥⾯的函数所以,⼤部分程序运⾏代码前会装⼊这个DLL,把⾥⾯的函数映射到⾃⼰的内存了这么⼀来,只要是这个DLL⾥⾯同⼀个函数在所有的进程⾥地址都是⼀样的哈哈,这样就容易了地址我们⼀般⽤GetProcAddressfunction GetProcAddress(hModule: HMODULE; //模块句柄,DLL被加载后就成⽴模块,等下告诉⼤家怎么得到这个lpProcName: LPCSTR//函数在DLL中的导出名LoadLibrary实际上是LoadLibraryA//这个⼤家看看DelphiWindows单元的源码就知道了): FARPROC; stdcall;//返回指针那些类型看得乱乱的吧,不要管他们,在Delphi上不⿏标停在函数上,类型的原型就出来了好了现在是怎么得到那个模块的句柄的问题⽤GetModuleHandlefunction GetModuleHandle(lpModuleName: PChar)//模块名,DLL被加载后就成⽴模块,所以就是DLL的⽂件名了: HMODULE; stdcall;//返回模块句柄好了.知道了这些得到函数地址就容易了GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA');⼀句搞定问题似乎都解决了吧先别⾼兴,不要忘记了,它还带了个参数,就是那个DLL的名字参数类型是⼀个指向字符串地址的指针这个是个⼤问题,⼀来你不能保证别⼈的程序内存⾥有这个字符串⼆来有你也不知道他的位置,这可怎么办呢⾃⼰写!我们把那个字符串写到对⽅内存⾥呵呵,很霸道的⽅法,但的确是个好⽅法不废话了,开始我们⾸先要在⽬标进程申请⼀块内存,以便把那个参数写进去申请内存⽤VirtualAllocEx,看看它的原型function VirtualAllocEx(hProcess: THandle;//⽬标进程句柄,这个不⽤说了吧lpAddress: Pointer;//分配内存位置,⼀般⽤nil,这样会在系统认为最合适的位置分配dwSize: DWORD;//分配的地址范围,也就是⼤⼩了flAllocationType: DWORD;//如何分配地址,⼀般⽤MEM_COMMIT为指定空间提交物理内存flProtect: DWORD//该段内存的保护类型,PAGE_READWRITE表⽰可读可写): Pointer; stdcall;//返回内存地址,哈哈,这就是我们要的那个参数的指针了好了,分配完内存当然是要把我们的数据写过去了这时候需要⽤到WriteProcessMemory来写进程的内存function WriteProcessMemory(hProcess: THandle; //⽬标进程句柄const lpBaseAddress: Pointer;//要写的内存地址,就填我们那个参数的指针lpBuffer: Pointer;//数据的地址,我们把字符串存这⾥,让他拷nSize: DWORD;//要拷贝的数据长度//字符串在Windows定义是以null(就是16进制的0)结尾的//所以长度就是字符串的长度+1var lpNumberOfBytesWritten: DWORD)//返回的什么东西,没什么⽤: BOOL; stdcall; //返回成功或失败我们来写个完整的代码吧procedure TmyForm.Button6Click(Sender: TObject);varh:longword; //放句柄,中间顺便暂放下PIDtmp:longword;//这个专门来占格式收集垃圾DllName:pchar;Mysize:longword;//放字符串长度Parameter:pointer;//放那个参数的指针(位置在⽬标进程内)beginDLLName:='Testdll.dll';Mysize:=strlen(Dllname)+1;winexec('notepad',1);GetWindowThreadProcessId(FindWindow('notepad', nil), @h);h:=OpenProcess(PROCESS_ALL_ACCESS, False, h);Parameter:= VirtualAllocEx(h, nil, Mysize, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(h, Parameter, Pointer(DllName), MySize, tmp);CreateRemoteThread(h,nil, 0, GetProcAddress(GetModuleHandle('KERNEL32.DLL'), 'LoadLibraryA'), Parameter, 0 , tmp);end;⼜看到那两个熟悉的对话框了哈哈,这么说我们成功了如把那个DLL换成其他的功能,那就...⼀个现成的调⽤代码:procedure Inject(ProcessHandle: longword; EntryPoint: pointer);varModule, NewModule: Pointer;Size, BytesWritten, TID: longword;beginModule := Pointer(GetModuleHandle(nil));//得到模块句柄,nil表⽰得到⾃⾝模块的Size := PImageOptionalHeader(Pointer(integer(Module) + PImageDosHeader(Module)._lfanew + SizeOf(dword) + SizeOf(TImageFileHeader))).SizeOfImage;VirtualFreeEx(ProcessHandle, Module, 0, MEM_RELEASE);NewModule := VirtualAllocEx(ProcessHandle, Module, Size, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE);WriteProcessMemory(ProcessHandle, NewModule, Module, Size, BytesWritten); CreateRemoteThread(ProcessHandle, nil, 0, EntryPoint, Module, 0, TID);end;⽤的时候写个⽆参数的函数(遵守标准调⽤)⽐如func吧inject(⽬标句柄,@func);就OK了注意那个func⾥⾯只能有API函数,⾃⼰写的函数都不能调⽤,想⽤就直接写过程进去吧不然会怎样你试试就知道了注意了VirtualAllocExVirtualFreeExCreateRemoteThread在NT下才能⽤转⾃:。
getthreadcontext failed的解决方法
GetThreadContext failed通常出现在Windows系统中,表示在尝试获取线程的上下文信息时遇到了问题。
这可能是由于多种原因,包括但不限于:1.权限问题:你可能没有足够的权限来访问或修改线程的上下文。
2.线程已经结束:如果线程已经结束,那么它的上下文可能已经不再可用。
3.驱动或内核问题:某些系统驱动或内核可能不兼容或不正确,导致无法获取线程上下文。
4.DLL或程序问题:加载的DLL或程序可能有问题,导致无法正确获取线程上下文。
为了解决这个问题,你可以尝试以下方法:1.检查权限:确保你有足够的权限来访问或修改线程的上下文。
你可能需要以管理员身份运行程序或使用更高权限的用户账户。
2.确保线程存在:确保你正在尝试访问的线程仍然存在。
如果线程已经结束,那么它的上下文可能已经不再可用。
3.更新驱动和系统:确保你的系统驱动和内核是最新的,并且与你的操作系统版本兼容。
如果可能,尝试更新或回滚驱动程序,看看是否可以解决问题。
4.检查程序和DLL:确保你正在使用的程序或加载的DLL没有损坏或不兼容的问题。
尝试重新安装或更新程序和DLL,看看是否可以解决问题。
5.查看系统日志:查看Windows事件查看器中的系统日志,看是否有与GetThreadContext failed相关的错误或警告信息。
这可能会提供更多关于问题的线索。
6.搜索在线资源:使用搜索引擎搜索GetThreadContext failed,看是否有其他用户遇到相同的问题,并查找他们的解决方案或建议。
7.联系技术支持:如果上述方法都无法解决问题,你可能需要联系软件供应商或系统制造商的技术支持部门,寻求更专业的帮助和支持。
在微服务环境下,远程调用feign和异步线程存在请求数据丢失问题
在微服务环境下,远程调⽤feign和异步线程存在请求数据丢失问题⼀、⽆异步线程得情况下feign远程调⽤:0、登录拦截器:@Componentpublic class LoginUserInterceptor implements HandlerInterceptor {public static ThreadLocal<MemberResVo> loginUser = new ThreadLocal<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取登录⽤户的键MemberResVo attribute = (MemberResVo) request.getSession().getAttribute(AuthServerConstant.LONG_USER);if (attribute!=null){loginUser.set(attribute);return true;}else {request.getSession().setAttribute("msg","请先进⾏登录!");response.sendRedirect("/login.html");return false;}}}1、问题⽰例图:解决⽅法:import feign.RequestInterceptor;import feign.RequestTemplate;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;@Configurationpublic class GuliFeignConfig {//fegin过滤器@Bean("requestInterceptor")public RequestInterceptor requestInterceptor() {return new RequestInterceptor() {public void apply(RequestTemplate template) {//上下⽂环境保持器,拿到刚进来这个请求包含的数据,⽽不会因为远程数据请求头被清除ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();//⽼的请求if (request != null) {//同步⽼的请求头中的数据,这⾥是获取cookieString cookie = request.getHeader("Cookie");template.header("Cookie", cookie);}}};}}⼆、异步情况下丢失上下⽂问题:①在同⼀线程下进⾏远程调⽤,即⼀连串调⽤的情况下OrederService通过远程调⽤先查找adress信息,再查找cart信息,则仅需配置GuliFeignConfig就够了②由于采⽤的异步任务,所以101、102线程在⾃⼰的线程中调⽤登录拦截器interceptor,⽽其实只有在72号线程中登陆拦截器才进⾏放⾏(有请求头数据),这就导致101、102的request为null解决⽅式(⾼亮部分):从总线中获取request数据放⼊⼦线程中@Service("orderService")public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {@AutowiredMemberFeignService memberFeignService;@AutowiredCartFeginService cartFeginService;@AutowiredThreadPoolExecutor executor;@AutowiredWmsFeignService wmsFeignService;/*** 订单确认页返回的数据* @return*/@Overridepublic OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {OrderConfirmVo confirmVo = new OrderConfirmVo();MemberResVo memberResVo = LoginUserInterceptor.loginUser.get();//从主线程中获得所有request数据RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {//1、远程查询所有地址列表RequestContextHolder.setRequestAttributes(requestAttributes);List<MemberAddressVo> address = memberFeignService.getAddress(memberResVo.getId());confirmVo.setAddress(address);}, executor);//2、远程查询购物车所选的购物项,获得所有购物项数据CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {//放⼊⼦线程中request数据RequestContextHolder.setRequestAttributes(requestAttributes);List<OrderItemVo> items = cartFeginService.getCurrentUserCartItems();confirmVo.setItem(items);}, executor).thenRunAsync(()->{RequestContextHolder.setRequestAttributes(requestAttributes);List<OrderItemVo> items = confirmVo.getItem();List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());//远程调⽤查询是否有库存R hasStock = wmsFeignService.getSkusHasStock(collect);//形成⼀个List集合,获取所有物品是否有货的情况List<SkuStockVo> data = hasStock.getData(new TypeReference<List<SkuStockVo>>() {});if (data!=null){//收集起来,Map<Long,Boolean> stocks;Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock)); confirmVo.setStocks(map);}},executor);//feign远程调⽤在调⽤之前会调⽤很多拦截器,因此远程调⽤会丢失很多请求头//3、查询⽤户积分Integer integration = memberResVo.getIntegration();confirmVo.setIntegration(integration);//其他数据⾃动计算CompletableFuture.allOf(getAddressFuture,cartFuture).get();return confirmVo;}}。
线程注入原理
线程注入原理全文共四篇示例,供读者参考第一篇示例:线程注入原理是指在计算机程序运行过程中,利用特定的技术手段向目标进程中注入一个线程,从而达到修改目标进程内部状态、窃取敏感信息等目的的一种攻击手法。
线程注入是一种常见的恶意软件攻击技朧,被广泛应用于计算机病毒、间谍软件、后门等恶意程序中。
线程注入的实现原理主要包括以下几个步骤:定位目标进程、创建注入线程、注入线程代码、执行注入线程。
具体来说,线程注入过程可以分为如下几个关键步骤:1. 定位目标进程:在进行线程注入之前,需要首先定位目标进程。
通过遍历系统中所有进程,寻找目标进程的进程标识符(PID),获取目标进程的句柄(handle),以便后续的注入操作。
2. 创建注入线程:接下来,利用系统API或其他相关工具,创建一个新的线程,并将目标进程的句柄与新线程进行关联。
新线程即为将要注入到目标进程中的恶意线程。
3. 注入线程代码:在创建完毕注入线程后,需要将恶意代码注入到新线程中。
恶意代码可以是实现特定功能的Shellcode或其他恶意程序代码。
这些代码可以用于获取敏感信息、执行恶意操作或者窃取目标进程的数据。
4. 执行注入线程:最后一步是执行注入线程。
将恶意线程注入到目标进程中,并通过线程调度器调度执行。
一旦注入线程被执行,恶意代码就会开始在目标进程的上下文中运行,实现对目标进程的攻击目的。
线程注入原理虽然可以实现一些恶意功能,但同时也具有一定的风险和局限性。
在实际应用中,线程注入可能会被杀毒软件、防火墙等安全工具检测到并拦截,从而无法顺利地执行。
另外,由于线程注入会直接修改目标进程的内部状态,存在导致目标程序崩溃或异常退出的风险,因此需要慎重使用。
总的来说,线程注入原理是一种常见的恶意攻击手法,通过向目标进程中注入恶意线程实现对目标进程的攻击。
在进行防范时,可以通过安全软件、补丁及权限控制等措施,有效减少线程注入攻击的发生。
同时,对于开发人员来说,在编写程序时应该严格控制进程间通信的权限,并对用户输入、外部调用等进行充分的检查和过滤,以防止恶意线程的注入。
concurrentexectiondisallowed
concurrentexectiondisallowed"ConcurrentExecutionDisallowed"是一个错误消息,它表示在并发执行期间发生了错误。
这个错误通常发生在多线程或多进程环境中,当一个操作正在执行时,另一个操作试图并发执行时会出现此错误。
具体来说,"ConcurrentExecutionDisallowed"错误可能是由以下情况引起的:1. 线程安全问题:在多线程环境中,如果多个线程同时访问共享资源而没有适当的同步机制,就会导致并发执行错误。
例如,当一个线程正在修改一个对象时,另一个线程试图同时访问或修改同一个对象。
2. 进程间通信问题:在多进程环境中,如果多个进程同时访问共享资源而没有适当的同步机制,就会导致并发执行错误。
例如,当一个进程正在写入一个文件时,另一个进程试图同时读取或写入同一个文件。
为了解决"ConcurrentExecutionDisallowed"错误,可以采取以下措施:1. 使用同步机制:在多线程或多进程环境中,可以使用锁、信号量、条件变量等同步机制来确保共享资源的互斥访问。
这样可以避免多个操作同时访问同一个资源。
2. 使用线程安全的数据结构:在多线程环境中,可以使用线程安全的数据结构来避免并发执行错误。
这些数据结构在内部实现了适当的同步机制,以确保多个线程可以安全地访问和修改数据。
3. 使用进程间通信机制:在多进程环境中,可以使用进程间通信机制来确保共享资源的互斥访问。
例如,可以使用管道、共享内存、消息队列等机制来实现进程间的同步和通信。
总之,"ConcurrentExecutionDisallowed"错误表示在并发执行期间发生了错误,可能是由于线程安全问题或进程间通信问题引起的。
通过使用适当的同步机制和数据结构,可以避免并发执行错误并确保多个操作可以正确地访问和修改共享资源。
一种防止远程线程注入的方法、装置及电子设备[发明专利]
专利名称:一种防止远程线程注入的方法、装置及电子设备专利类型:发明专利
发明人:周鹏,王广彬
申请号:CN201710534027.2
申请日:20170703
公开号:CN107273743A
公开日:
20171020
专利内容由知识产权出版社提供
摘要:本发明公开一种防止远程线程注入的方法、装置及电子设备,涉及安全防护技术领域,能够保护应用程序的正常运行,以及防止远程破坏。
所述防止远程线程注入的方法,包括:根据对线程创建的调用的监视,获取待创建线程所归属的进程的标识信息,判断待创建线程所属进程是否是要保护的进程,若是,则获取发起所述待创建线程的进程的标识信息,根据发起创建所述线程的进程的标识信息,判断所述发起创建线程的进程是否是目标应用程序的进程,若否,与此同时目标应用程序的线程数大于0则拒绝创建所述待创建线程。
所述装置和电子设备中包括实现上述方法步骤的模块。
本发明适用于对应用程序尤其是对基础类应用程序的保护。
申请人:西安新路网络科技有限公司
地址:710000 陕西省西安市高新区科技二路68号西安软件园秦风阁H102
国籍:CN
代理机构:西安毅联专利代理有限公司
代理人:王宗江
更多信息请下载全文后查看。
electron error invoking remote method
你遇到的问题是Electron中的错误,它发生在尝试调用远程方法时。
这可能是由于多种原因,包括但不限于:
远程方法的定义或实现存在问题。
通信协议或数据格式不正确。
进程间通信(IPC)出现问题。
要解决这个问题,你需要先确定具体是哪个环节出现了问题。
以下是一些可能的解决步骤:
检查远程方法的定义和实现,确保它们是正确的,并且可以正常工作。
检查通信协议和数据格式,确保它们是正确的,并且可以被正确解析和生成。
检查IPC通信,确保它正常工作。
你可以使用调试工具或日志记录来查看IPC通信的具体情况。
如果上述步骤都无法解决问题,你可能需要更深入地查看错误消息或堆栈跟踪,以了解错误发生的具体位置和原因。
如果你能提供更多关于你的代码和错误的详细信息,我可能能够提供更具体的帮助。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
远程线程注入时遇到的问题
这是我在研究程序自我删除(关于程序自我删除相关的技术我会在之后的文章中详细介绍)技术中碰到的问题, 暂时没有找到原因及解决办法. 暂且记录下来方便日后查阅、分析.
CreateRemoteThread经常在木马病毒中使用, 最常见的做法就是把LoadLibrary当作线程函数在目标进程中动态加载自己的Dll, 这种方法比通过HOOK加载Dll的优点在于不需要目标进程依赖于User32.dll. 但是在实际使用过程中确会遇到不少问题.
除了使用LoadLibrary作为线程函数我们可以使用自定义的线程函数, 当然前提是这个线程函数的二进制代码已经正确无误地插入到目标进程. 具体方法这里不便展开.
AdjustTokenPrivileges:
首先碰到的问题是关于进程权限问题, 确切的来说也不是问题, 只是在开发过程中遇到的比较奇怪的现象, 仅仅记录下来方便日后研究. 在此之前一直没有搞清楚提高进程权限是什么意思, 难道是提高系统级?
当然不可能, 微软不傻. 经过一些测试我有了一些发现. 代码如下:
[c-sharp]view plaincopy
1.BOOL EnableDebugPrivilege()
2.{
3. HANDLE hToken;
4.if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToke
n) != TRUE)
5. {
6.return FALSE;
7. }
8.
9. LUID Luid;
10.if(LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid) != TRUE)
11. {
12.return FALSE;
13. }
14.
15. TOKEN_PRIVILEGES tp;
16. tp.PrivilegeCount = 1;
17. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
18. tp.Privileges[0].Luid = Luid;
19.
20.if(AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), N
ULL, NULL) != TRUE)
21. {
22.return FALSE;
23. }
24.
25.return TRUE;
26.}
测试结果如下:
1. 使用该函数->枚举进程. 结果显示枚举到进程67个, 但是任务管理器显示当前进程73个. 未解.
2. 不使用该函数->OpenProcess打开系统进程失败.
这里有两个例外:
1. 在我电脑上(win7 x86)有一个进程名为SearchFilterHost.exe在任务管理器中显示为系统进程, 但是OpenProcess还是能成功.
2. 如果从vs启动, 结果同1.
在win7 x64上再次测试, 暂时没有发现SearchFilterHost这样的例外. 这里我说的系统进程暂时理解为任务管理器显示用户名为SYSTEM的进程. 不知是否正确.
枚举进程使用了CreateToolhelp32Snapshot/EnumProcesses两种方法, 情况相同.
CreateRemoteThread:
接下来遇到的问题是CreateRemoteThread时遇到的问题, 测试环境:win7 x86 + win7 x64. 首先我把CreateRemoteThread成功的例子整理一下(我们自己的进程名字暂时叫self.exe):
1. 平台:x86. self.exe:x86. 目标进程:非系统进程.
2. 平台:x64. self.exe:x86. 目标进程:32位非系统进程.
3. 平台:x6
4. self.exe:x64. 目标进程:64位非系统进程.
接下来是CreateRemoteThread调用失败的一些情况:
1. 平台:x86. self.exe:x86. 目标进程:系统进程.
GetLastError()==8. 描述: Not enough storage is available to process this command.
2. 平台:x64. self.exe:x86. 目标进程:64位进程. (包括用户进程和系统进程)
GetLastError()==5. 描述: Access Denied.
3. 平台:x6
4. self.exe:x86. 目标进程:32位系统进程.
GetLastError()==8. 描述: Not enough storage is available to process this command.
4. 平台:x64. self.exe:x64. 目标进程:64位系统进程.
GetLastError()==8. 描述: Not enough storage is available to process this command.
5. 平台:x64. self.exe:x64. 目标进程:32位系统进程.
GetLastError()==8. 描述: Not enough storage is available to process this command.
6. 平台:x64. self.exe:x64. 目标进程:32位非系统进程.
成功!但是直接导致目标进程崩溃.
为了跟使我们的结果更加清晰, 我们将它汇总到下面的表格中:
汇总结果如下:
1. 在x64平台上用x86进程注入x64进程. Access Denied.
2. 除1外, 任何情况只要是注入系统进程的. Not enough storage is available to process this command. 这里有个例外就是winlogon.exe
3. 剩下情况如果是注入进程与目标进程相容(都是x86或者都是x64), 注入成功. 这个是我们意料之中的.
4. 如果是x64进程注入x86进程. 注入成功但是目标进程崩溃. 这个想来也合理, 因为x64位编译出来的注入函数也是64位的, 必崩溃无疑. 理论上只要直接注入的函数/数据没问题就可以成功, 有兴趣的话可以用shellcode尝试一下, 也就是先用x86编译出来相关的数据和代码, 然后以二进制的方式提取出来, 再以二进制的方式写入远程线程. 这样就不必关心当前进程是x86的还是x64的. 这里还有一个问题就是为什么第一种情况下(x86进程注入x64进程(用户进程))会失败, 没有给我们任何使用shellcode的机会.
写到这儿, 我已经打算动手下一篇文章: 自删除问题的研究。
这是一个很有趣的话题, 其中也不乏一些堪称'天才'的杰作. 有兴趣的读者千万不要错过.。