首页
社区
课程
招聘
[原创]几种常见的注入姿势
发表于: 2018-5-29 22:14 23658

[原创]几种常见的注入姿势

2018-5-29 22:14
23658

来到看雪也快1年了,非常喜欢这个圈子,大家可以一起学习技术,希望看雪也能越来越好吧!

 

在厚颜无耻的求波文化衫。言归正传:

 

这篇原来是我博客里面的东西,标题是用户态下的Rootkit技术,其实说到Rootkit,心里还是非常慌张的,因为这些只是普通的注入和hook,但是有些书上是这样写的,所以呢,我在厚颜无耻的给他冠以更加高级的名字---Rootkit,因为博客直接是markdown写的,今天刚刚写完一套四级(原谅我就是这样菜),时间不是很早了,所以直接就粘贴复制了,如果有排版错误,我在修改修改!,小小小菜鸟一枚,欢迎各位师傅指正。本文的参考来源我附在最后一部分了。

第一部分:Rootkit技术

      Rootkit被计算机病毒广泛适用于躲避杀毒软件的查杀,RootKit技术也叫进程隐藏技术,掌握这项技术,这是一个“优秀”的病毒编写者应该具备的能力。同样的,对于病毒分析者来说,识别这种技术也是必须具备的。Rootkit技术主要有4种方法,分别是DLL注入,代码注入,HOOK技术,APC注入技术。这些技术都是把恶意代码注入到进程(线程)中,一般用procexp能看到。
<!-- more -->

第二部分:DLL注入

DLL注入的第一种方法:CreateRemoteThread远程线程调用

      DLL注入是指向某一个特定的进程空间强制插入一个特定的DLL文件映像,值得注意的是这种插入是强制性的插入,从技术层面来看,DLL注入是利用LoadLibrary()加载特定的DLL文件到进程的内存空间。注入的对象是可以是自身,也可以是远程进程。DLL注入技术实现主要分为5个部分,

  • 第一步打开进程,获取进程的句柄,
  • 第二歩是在内存空间开辟一段内存空间
  • 第三步是向刚刚开辟的内存中写入需要注入DLL的路径,
  • 第四步是利用GetProcessAddree()获取LoadLibrary的地址。
  • 第五步是调用远程线程,利用LoadLibrary()去加载DLL。
    bool InjectDll(DWORD dwPID, LPCTSTR szDLLPath)
    {
      HANDLE hProcess = NULL,hThread=NULL;
      DWORD BufSize = (DWORD)(_tcslen(szDLLPath) + 1) * sizeof(TCHAR);
      /*-------------打开需要注入的进程-------------*/
      if (!OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID))
      {
          printf("OpenProcess(%d) Open Fail:[%d]", dwPID, GetLastError());
          return 0;
      }
      /*------------向目标进程开辟内存空间-----------*/
      LPVOID pRemoteBuf = VirtualAllocEx(hProcess, NULL, BufSize, MEM_COMMIT, PAGE_READWRITE);
      /*------------将目标路径写入进程---------------*/
      WriteProcessMenory(hProcess, pRemoteBuf, (LPVOID)szDLLPath, BufSize, NULL);
      /*-----------获取LoadLibrary地址--------------*/
      HMODULE hMod = GetModuleHandle(L"kenerl32.dll");
      pThreadProc = GetAddress(hMod, "LoadLibrary");
      /*------------调用远程线程加载DLL--------------*/
      hThread = CreateRemoteThread(hProcess,
          NULL,
          0,
          pThreadProc,  //远程线程LaodLibrary
          pRemoteBuf,   //参数,DLL的路径
          0,
          NULL);
      CloseHandle(hProcess);
      CloseHandle(hThread);
      return 1;
    }
    
  • 反编译如下:

    • 打开进程

    • 设置进程内存空间

    • 调用CreateRemoteThread实现注入

DLL注入的第二种方法:利用注册表注入

      利用APPiNIT_dll注册表来实现DLL注入。因为windows允许只要加载了USER32.dll的进程并且,某一个dll的绝对路径处于注册表

 

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion \Windows\AppInit_DLLs中,os就会自动去加载位于该注册表的有效的DLL。所以只需要在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion \Windows\AppInit_DLLs中添加DLL的绝对路径,并把数值改为1,可以使得所有加载USER32.dll的进程全部加载目标路径的DLL。
      利用AppCertDlls注册表,将HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls下写入dll的路径,可以将此注册表项下的DLL加载到调用CreateProcess,CreateProcessAsUser,CreateProcessWithLogonW,CreateProcessWithTokenW和WinExec的每个进程中。值得注意的是win xp-win 10 默认不存在这个注册表项

DLL注入的第三种方法:SetWindowsHookEx()设置钩子

      利用windows的消息机制,可以在事件发送到os之间设置一条钩链,来钩取不同的消息,如以下代码,利用SetwindowsHookEx可以钩取一个键盘消息。并且调用钩子处理函数来处理这个消息,所达到的效果和dll注入是一样的(执行dll内部的代码)

extern "C" _declspec(dllexport) void HookStart()
{
    g_hHook = SetWindowsHookEx(WH_KEYBOARD, HookProc, GetModuleHandle(TEXT("消息钩取(DLL注入)实验.dll")), 0);
    if (g_hHook == NULL)
        MessageBox(NULL, TEXT("安装钩子失败"), TEXT("提示"), MB_OKCANCEL);
}

      钩子函数要使用回调函数,这样可以重复钩取消息

LRESULT CALLBACK HookProc(int ncode, WPARAM wParam, LPARAM lParam)
{
    FILE *fp;   //做文件的写入工作
    TCHAR key[20];            
    const TCHAR *k = NULL;
    TCHAR *p = NULL;
    if (ncode >= 0)  //ncode 大于等于0,操作有效
    {
        if (!(lParam & 0x80000000))//出现按键消息
        {
            GetKeyNameText(lParam,key,20);//检索键名的字符串
            int state = GetKeyState(VK_CAPITAL);//指定大小写的状态,返回值是1或者0
            int asyncState = GetAsyncKeyState(VK_SHIFT);//指定函数调用时候
            if (lstrlen(key) == 1)  //只出现一个按键
            {
                if (asyncState < 0)  //未上档
                {
                    for (int i = 0; i < 22; i++)
                    {
                        if (KeyUn[i] == key[0])
                        {
                            key[0] = KeyUn[i];
                            break;
                        }
                    }
                    if (k == NULL&&state > 0)  //小写状态
                    {
                        if (wParam >= 65 && wParam <= 90)
                            key[0] += 32;   //转化为ASCII小写
                    }
                }
                else  //小写状态
                {
                    if (k == NULL&&state == 0)
                    {
                        if (wParam >= 65 && wParam <= 90)
                            key[0] += 32;   //转化为小写
                    }
                }
                k = &key[0];         //k指向缓冲区的地址
            }
        }
        else if (lstrlen(key) == 5)
        {
            if (key[0] == TEXT('N') && key[1] == TEXT('u') && key[2] == TEXT('m') && key[3] == TEXT(' '))
                k = &key[4];
        }
        if (k != NULL)
        {
            lstrcat(str,k);
            //FlushBuffer();
            /*HANDLE hf = CreateFile(TEXT("C:/数据.txt"), GENERIC_READ | GENERIC_WRITE,
                0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);    
            if (!GetProcessId(NULL))
                ErrorExit(TEXT("GetProcessId"));
            DWORD written;
            WriteFile(hf, str, sizeof(str), &written, 0);
            CloseHandle(hf);*/
            fp = fopen("E:/学习/C语言/Viusal Studio/消息钩取(DLL注入)实验--注入工具(GUI)/消息钩取(DLL注入)实验--注入工具(GUI)/抓取的数据.txt", "wt");
            //fprintf(fp, "%s", str);
            //fwrite(str,sizeof(str),1,fp)
            if(fwrite(str, sizeof(str), 1, fp)!=1)
                MessageBox(NULL, TEXT("文件写入失败"), TEXT("提示"), MB_OKCANCEL);
            fclose(fp);
        }
    }
    //如果没有找到notepad的进程,将消息传递给下一个钩子
    return CallNextHookEx(g_hHook, ncode, wParam, lParam);
}

Dll注入的第四种方法:dll搜索劫持结束(也称dll加载顺序挟持)[Dll Search Order Hijacking]

      dll搜索劫持技术是一种简单的dll注入技术,他利用windows加载dll目录的优先级来加载dll。他不需要通过修改注册表或者修改二进制文件的前提下注入dll的。下面是windows加载dll的默认搜索顺序:

  • 1.加载应用程序的目录
  • 2.当前目录【经常利用到】
  • 3.系统目录(../windows/system32)
  • 4.16位子系统目录(../windows/system)
  • 5.windows目录(../windows)
  • 6.PATH环境变量列举的目录
  • 说明:为了安全和加载速度,windows会在HKML\System\CurrentSet\SessionManger\SafeDll\SafeDllSearchMode下创建键值,系统会优先加载这些已知的dll(第一位)
          我们在通过两个方面来进行劫持:
  • 1.通过在上述注册表中添加恶意dll路径的键值,这样使得恶意dll优先注入到进程空间(这个恶意dll需要和系统dll同名)
  • 2.在加载系统dll之前加载,
          有权访问文件系统的攻击者可能会将恶意ntshrui.dll放在C:\ Windows目录中。该DLL通常驻留在System32文件夹中。进程explorer.exe也驻留在c:\Windows中,一旦尝试从System32文件夹中加载ntshrui.dll,实际上会由于优先搜索顺序而加载由攻击者提供的DLL。由于攻击者已将其恶意ntshrui.dll放入与加载explorer.exe进程相同的目录中,因此将首先找到攻击者提供的DLL,从而加载代替合法DLL。由于explorer.exe在引导周期内被加载,攻击者的恶意软件被保证执行。【不上书上说的../windows比系统目录优先搜索,而是当前目录比系统目录被优先搜索】
          如果启用windows的Dll的安全检查,情况可能会大有改观。
    启用"安全DLL查找模式"时,查找顺序如下:
  • 1.应用程序所在目录;
  • 2.系统目录。GetSystemDirectory返回的目录,通常是系统盘\Windows\System32;
  • 3.16位系统目录
  • 4.Windows目录。GetWindowsDirectory返回的目录,通常是系统盘\Windows;
  • 5.当前目录。GetCurrentDirectory返回的目录;
  • 6.环境变量PATH中所有目录。

第三部分:代码注入

      代码注入是一种向进程中插入一段独立运行的代码并且不会影响进程的运行(如崩溃)的技术,从技术上讲他也是调用CreateRemoteThread()来注入远程代码。分两次向进程中注入,第一次以远程线程的形式注入,第二次以线程参数的形式注入远程进程。

DWORD WINAPI ThreadProc()
{
    //需要注入的代码
}
BOOL InjectCode(DWORD pId)
{
    PHANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID));
    dwsize = sizeof(THREADPARAM);   //插入代码所需要数据的大小
    pRemoteBuf[0] = VirtualAllocEx();   //在进程空间开辟一个数据大小相同的空间
    WriteProcessMenory(hProcess, pRemoteBuf[0], &param, dwsize, NULL);//将注入代码所需要的数据写入进程空间
    dwsize = (dword)InjectCode() - (dword)ThreadProc();//插入代码需要的空间大小
    pRemoteBuf[0] = VirtualAllocEx();    //在进程中开辟等大小的空间用于存储代码
    WriteProcessMenory(hProcess, pRemoteBuf[0], (LPVOID)ThreadProc(), dwsize, NULL);
    hTread = CreateRemoteThread(hProcess, 
                                NULL,
                                0,
                                pRemoteBuf[1], //注入的代码
                                pRemoteBuf[0], //代码所需要的数据作为代码的参数传入
                                0, NULL);
    CloseHandle(hProcess);
    CloseHandle(hThread);
}
  • 反编译如下:

    • 复制代码所需数据

    • 打开目标进程:

    • 开辟内存空间,为了存储数据

    • 写入数据

    • 开辟进程空间,为了存储代码

    • 写入代码

    • 调用CreateRemoteThread()进行代码注入

第四部分:HOOK技术

      HOOK叫做钩取(钩子),他的原理是:windows系统分为用户态和内核态,在用户态中需要访问一些敏感的数据(网络,文件资源等)就必须要调用windowsAPI函数,来与kernel沟通获得该资源的使用权。钩子便可以这是在调用API函数的时候,在调用之前(IAT_HOOK)或者之后发挥作用,这样恶意软件便不需要创建一个进程就可以实现某些恶意的功能。便达到了隐藏自身的作用。

1.IAT_HOOK技术【复杂且不友好】

      在一个windows应用程序中,人们所编写的代码所占的比例不到20%,其他都是导入的是库文件(windows下主要是dll文件),dll文件的存在大大简化了人们的工作,同样的也减少了程序所运行的成本,因为在一个dll文件中不是所有函数都会被使用。在.exe文件中存在一个叫做IAT(导入地址表)的表,这个表存在的原因就是便于程序去dll文件中寻找特定的函数。

 

      一个正常的exe使用IAT的过程如下:程序调用了某个dll中的函数,首先回去程序自带的IAT中寻找改函数在dll中所处的地址,然后调用一个jmp跳转到dll!FUN()所在的地址,继续执行。【windows加载器会在程序运行时把dll中函数的地址存储在IAT中,当然程序第一个调用的是IAT的地址】

 


      如果程序被IAT_HOOK的话,过程是这样的。首先先使用DLL注入把含有恶意代码的DLL注入到进程内部,并修改IAT数据,程序和正常过程一样调用IAT的地址,但是此时IAT的函数地址并不是正常的函数地址,jmp到恶意的函数中执行,执行完恶意代码后call到正常的dll中。然后retn。

2.InLine_HOOK技术

      InLine_HOOK技术和IAT_HOOK技术同样是钩取需要调用的API函数,区别在于InLine_HOOK并不是钩取IAT的数据,而是直接修改API函数内前5个字节,将其修改为JMP XXXXXXXX(恶意代码地址)。当然在修改后要恢复修改的内容以便原函数能够正确的执行。

 

      基本过程如下:正常调用API,在钩取前要修改原函数前5个字节,(1)做一个JMP,跳转到恶意代码,利用寄存器存储恶意代码地址,(2)然后跳转到原函数,还原原函数开始的前五个字节,以便正常执行原函数,(3)利用之前存储的地址,我们call过去,这样就到达了恶意代码处,(4)恶意代码执行完毕,返回正常执行原API函数,(5)最后返回用户领空.

      下面是一次关于InLine_HOOK的分析案例:

  • 在这里,先是利用App_Lnit技术加载了恶意的dll.以便后续的钩取。
  • 然后暂定线程,以便后续修改函数
  • 程序首先对进程进行快照,在快照列表中寻找符合要求的进程名,如果有则下一步
  • 先获取当前的进程ID,然后把wsock32.dll和send函数作为参数压入。
  • 如图,a2是钩取函数的地址,a2-ipAddress是为了获得两个进程的相对距离,-5是为了获得jmp xxxxxxxxx的大小,然后调用VirtuaProtect获得进程内存的权限。以便下面的修改,修改之后继续调用VirtaulProtect恢复进程原来状态
  • 最后恢复执行线程

第五部分:APC注入

      APC是一个链状的数据结构,可以让一个线程在其本应该的执行步骤前执行其他代码,每个线程都维护这一个APC链,他在线程处于可警告的等待状态时被执行。恶意代码为了使得自己立即被执行,他们会利用APC抢占处于等待状态的线程。

用户模式下的APC注入

      程序利用QueueUserAPC()函数调用远程函数,该函数的参数为pfnAPC,hThread,dwData,(1)目标线程的句柄; 2)指向恶意软件想要运行的函数指针; 3)和传递给函数指针的参数)。其要求hThread调用数值为dwData的pfnAPC定义的函数。当然线程处于等待状态是APC注入的前提,一般的注入svchost.exe,我们也可以调用SleepEx,SignalObjectAndWait,MsgWaitForMultipleObjectsEx,WaitForMultipleObjectsEx或WaitForSingleObjectEx函数,线程将进入可警醒状态。

push [esp+dwThreadId]
push 0
push 10h
call ds:OpenThread
mov esi,eax
test esi,esi
jz short Loc_401DCE
push [esp+dwData]    ;dbnet.dll
push esi             ;hThread
push ds:LoadLibraryA ;pfnAPC
call ds:QueueUserAPC
;调用QueueUserAPC对pThread进程调用参数为dbnet.dll的LoadLibrary函数

内核模式下的APC注入

      利用KeInitializeAPC()和KeInsertQueueAPC()进行APC注入。

第六部分:进程替换技术(进程hollowing)

      除了注入之外,我们还可以使用进程替换技术将一个可执行文件写入一个运行的进程内部,这种技术让恶意代码拥有和被替换进程相同的特权,这个技术关键是:需要以挂起状态创建进程,也就是说,这个进程将会被载入内存,但是主线程过去,在外部程序恢复主线程之前,程序不会工作,恢复主线程之后,程序工作。如下代码是进程替换代码的伪代码.该程序通过调用CreateProcess并将进程创建标志设置为CREATE_SUSPENDED(0x00000004)完成。新进程的主线程被创建为挂起状态,直到ResumeThread函数被调用才会运行。接下来,恶意软件需要用恶意的有效载荷来替换合法文件的内容。这可以通过调用ZwUnmapViewOfSection或NtUnmapViewOfSection来取消映射目标进程的内存(这一步的目的在于是重新写入傀儡进程的时候,进程对于这部分待注入的内存还有所有权,为了避免冲突,在重写入进程之前,需要取消进程对内存的映射)。这两个API基本上释放了一个部分指向的所有内存。现在内存被取消映射,加载器执行VirtualAllocEx为恶意软件分配新内存,并使用WriteProcessMemory将每个恶意软件的部分写入目标进程空间。恶意软件调用SetThreadContext将entrypoint指向已编写的新代码段。最后,恶意软件通过调用ResumeThread来恢复挂起的线程。

CreateProcess(...,"目标进程.exe",CREATE_SUSPENDED);//以挂起状态创建进程
ZwUnmapviewOfSection()                             //释放内存,解除内存映射
VirtualAllocEx()                                   //为恶意代码分配新空间
writeProcessMenory(header)                         //写入数据(文件头)
for(i=0;i<NumberOfSection;i++)
    WriteProcessMenory(section)                    //写入节区数据
···
ResumeThread()                                     //重新启动主线程


      还有一个类似于进程hollowing的技术,叫做线程执行劫持。他针对进程中的现有线程,避免产生其他新的线程,先是查找线程,并且利用openThread打开目标线程,在获取目标线程的句柄后,恶意软件通过调用SuspendThread来将线程置于挂起模式。调用VirtualAllocEx和WriteProcessMemory来分配内存并执行代码注入的操作。然后调用GetThreadContext和GetThreadContext获取并设置线程的上下文,以将EIP寄存器设置到要执行恶意代码的地址,达到重启线程的作用。

第七部分:PE注入

      这个技术类似于代码注入,但是与代码注入有所不同,更加像是把整个pe文件注入到进程,操作方法与进程替换的步骤又有所相像。这里暂时不做理会。

第八部分:通过SETWINDOWLONG 进行窗口内存注入 (EWMI)

      EWMI依靠注入资源管理器托盘窗口的额外窗口内存,并在恶意软件家族中被多次使用使用,如Gapz和PowerLoader。在注册窗口类时,应用程序可以指定一些额外的内存字节,称为额外的窗口存储器(EWM)。 然而,EWM并不算是块很充裕的空间。 为了规避这个限制,恶意软件将代码写入explorer.exe的共享部分,并使用SetWindowLong和SendNotifyMessage来指定一个指向shellcode的函数指针,然后执行它。当涉及到向共享部分的写入数据时,恶意软件有两个选择:它可以也创建一个共享空间,并将其映射到自身和另一个进程(例如,explorer.exe);第二个选择就是简单地打开已经存在的共享部分。 前者具有分配堆空间和调用NTMapViewOfSection以及其他一些API调用的开销,因此后一种方法被更频繁地使用。 恶意软件在共享部分中写入其shellcode后,使用GetWindowLong和SetWindowLong访问并修改“Shell_TrayWnd”的额外窗口内存。 GetWindowLong是用于将指定偏移量的32位值检索到窗口类对象的额外窗口存储器中的API,SetWindowLong用于更改指定偏移量的值。 通过这样做,恶意软件可以简单地更改窗口类中的函数指针的偏移量,并将其指向写入共享部分的shellcode。像上面提到的大多数其他技术一样,恶意软件需要触发它编写的代码。 在以前讨论的技术中,恶意软件通过调用API(如CreateRemoteThread,QueueUserAPC或SetThreadContext)来实现这一点。 在EWMI方法中,恶意软件通过调用SendNotifyMessage触发注入的代码。 在执行SendNotifyMessage之后,Shell_TrayWnd接收并将控件传递给由SetWindowLong先前设置的值指向的地址。 在图13中,名为PowerLoader的恶意软件使用这种技术。

第九部分:SHIMS注入

      Microsoft向开发人员提供了Shims[译者注:Shim是一个工程术语,描述为了让两个物体更好地组装在一起而插入的一块木头或金属。在计算机编程中,shim是一个小型的函数库,用于透明地拦截API调用,修改传递的参数、自身处理操作、或把操作重定向到其他地方。Shim也可以用来在不同的软件平台上运行程序。],主要是为了向后兼容。 Shims允许开发人员将修补程序应用于程序,而无需重写代码。 通过利用Shims,开发人员可以告诉操作系统如何处理其应用程序。 Shims本质上是一种嵌入API并针对特定可执行文件的方式。 恶意软件可以利用Shims来实现注入可执行文件并维持注入。 Windows运行Shim引擎时,它加载二进制文件以检查shimming数据库,以便应用适当的修补程序。有许多可以使用的修复程序,但是恶意软件还是更偏爱那些安全相关的(例如DisableNX,DisableSEH,InjectDLL等)。要安装shimming数据库,恶意软件可以使用各种方法。 例如,一个常见的方法是简单执行sdbinst.exe,并将其指向恶意的sdb文件。 在图14中,广告软件“Search Protect by Conduit”使用Shims进行注入和维持。 它在Google Chrome中执行“InjectDLL”shim以加载vc32loader.dll。 现在有一些用于分析sdb文件的工具,但是对于下面列出的sdb的分析,我使用了python-sdb,而没有使用现成的工具。

第十部分:说明

      这篇博客,我主要参考的是逆向工程核心原理23.27.30-32等章节和恶意代码分析实战,以及来自看雪的一篇文章https://bbs.pediy.com/thread-220500.htm。文章的主要内容是2-7部分,第8.9两部分是摘录自看雪。先写了关于本文的前7章内容,随后看了看雪的这篇文章,里面介绍的内容和原来和很多相同,所以不做摘录,关于进程替换技术原来使用得是ResumeThread()API调用重启进程,也可以使用SetThreadContext来设置EIP为恶意代码入口。在线程执行劫持部分有所体现。关于AppCertDlls注册表注入部分。注册表项HKLM\System\CurrentControlSet\Control\Session Manager\AppCertDlls可能需要自己写入。因为AppCertDlls并不存在。


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2019-2-2 14:45 被kanxue编辑 ,原因:
收藏
免费 11
支持
分享
最新回复 (25)
雪    币: 6366
活跃值: (4336)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
辛苦整理,感谢分享,收藏
2018-5-29 22:20
0
雪    币: 285
活跃值: (1090)
能力值: ( LV13,RANK:405 )
在线值:
发帖
回帖
粉丝
3
rootkit还是动ssdt比较多吧,注射技术严格来讲应该不能算是rootkit吧
2018-5-29 22:35
0
雪    币: 498
活跃值: (2234)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
4
sudozhange rootkit还是动ssdt比较多吧,注射技术严格来讲应该不能算是rootkit吧
前面我写了的,
2018-5-29 22:40
0
雪    币: 367
活跃值: (178)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5

最后于 2018-5-30 09:29 被DCounter编辑 ,原因:
2018-5-29 23:57
0
雪    币: 23080
活跃值: (3432)
能力值: (RANK:648 )
在线值:
发帖
回帖
粉丝
6
为了T恤,你也是蛮拼的,赞一个
2018-5-30 00:37
0
雪    币: 498
活跃值: (2234)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
7
KevinsBobo 为了T恤,你也是蛮拼的,赞一个[em_63]
主要有纪念意义,这次T恤组真的漂亮
2018-5-30 00:44
0
雪    币: 498
活跃值: (2234)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
8
嗯嗯,已修改,确实有这个嫌疑,不过每个人有每个人的理解嘛
2018-5-30 00:49
0
雪    币: 8
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
非常有学习价值,顶一个。
2018-5-30 02:48
0
雪    币: 0
活跃值: (143)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
感谢楼主发帖
2018-5-30 10:15
0
雪    币: 4161
活跃值: (767)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
收藏一波
2018-6-1 00:10
0
雪    币: 310
活跃值: (2232)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
谢谢楼主整理,
2018-6-1 07:47
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感谢整理
2018-6-1 23:35
0
雪    币: 471
活跃值: (3718)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
14
EWMI和SHIMS注入    学习了
2018-6-3 21:35
0
雪    币: 264
活跃值: (184)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
15
emmm  好像在国外的博客看到过一个类似的
2018-6-6 21:50
0
雪    币: 498
活跃值: (2234)
能力值: ( LV12,RANK:356 )
在线值:
发帖
回帖
粉丝
16
wx_sw emmm 好像在国外的博客看到过一个类似的
对,十种常见的注入方式,有参考
2018-6-7 10:37
0
雪    币: 2694
活跃值: (80)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
17
学习了
2018-6-13 08:48
0
雪    币: 2391
活跃值: (309)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
18
mark
2018-9-20 19:22
0
雪    币: 688
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
Mark
2018-12-5 11:08
0
雪    币: 419
活跃值: (96)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
mark 学习
2019-7-22 12:08
0
雪    币: 1128
活跃值: (72)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
学习了,感谢楼主分享
2019-7-22 14:13
0
雪    币: 244
活跃值: (169)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
有demo嘛?
2019-10-16 15:12
0
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
注入也可以参考这里系列的文章 非常不错 https://www.miao1yan.top/forum.php?mod=forumdisplay&fid=89
2019-10-16 18:19
0
雪    币:
活跃值: (421)
能力值: ( LV5,RANK:73 )
在线值:
发帖
回帖
粉丝
24
很详细,mark了,可以随时查
2020-5-1 14:37
0
雪    币: 164
活跃值: (70)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
非常感谢
2020-8-28 11:26
0
游客
登录 | 注册 方可回帖
返回
//