看流星社区

 找回密码
 注册账号
查看: 1894|回复: 0

DLL注入相关

[复制链接]

该用户从未签到

发表于 2017-6-1 13:33:22 | 显示全部楼层 |阅读模式
先说说DLL引用的方法:
如果有lib+dll+头文件
则:建工程的时候选择导出符号

#pragma comment(lib, “libname.lib”)
#include “libname.h”
func();[/code]只有DLL文件

LoadLibrary
GetProcAddress


因为在C++中有函数重整,(函数名会被自动改变),我们需要在DLL中,在函数前加上

extern "C"[/code]声明是C函数,不要重整函数


SetWindowsHookEx 全局钩子

HHOOK WINAPI SetWindowsHookEx(
__in int idHook, \\钩子类型
__in HOOKPROC lpfn, \\回调函数地址
__in HINSTANCE hMod, \\包含lpfn的实例句柄
__in DWORD dwThreadId); \\线程ID,如果为0,则监控所有线程的全局钩子


WH_CALLWNDPROC and WH_CALLWNDPROCRET
WH_CBT
WH_DEBUG
WH_FOREGROUNDIDLE
WH_GETMESSAGE
WH_JOURNALPLAYBACK
WH_JOURNALRECORD
WH_KEYBOARD_LL
WH_KEYBOARD
WH_MOUSE_LL
WH_MOUSE
WH_MSGFILTER and WH_SYSMSGFILTER
WH_SHELL


得到控制权的钩子函数在完成对消息的处理后,如果想要该消息继续传递,那么它必须调用另外一个SDK中的API函数CallNextHookEx来传递它。钩子函数也可以通过直接返回TRUE来丢弃该消息,并阻止该消息的传递。


更多钩子https://msdn.microsoft.com/en-us/library/ms644959(VS.85).aspx





全局钩子:
实现文件如下。其中g_hWnd为所有进程共享,并且绕过了系统对可写数据的写时复制机制,维护的是一份拷贝


// Hook.cpp  
#include <windows.h>  
HHOOK g_hMouse = NULL;  
HHOOK g_hKeyboard = NULL;  
// 为Hook.DLL创建一个新的节,将全局变量g_hWnd放入其中  
#pragma data_seg("MySec")  
HWND g_hWnd = NULL;  
#pragma data_seg()  
// 设置刚创建的节为共享的节  
#pragma comment(linker, "/section:MySec,RWS")  
// 鼠标钩子过程  
LRESULT CALLBACK MouseProc(  
                           int nCode,      // hook code  
                           WPARAM wParam,  // message identifier  
                           LPARAM lParam   // mouse coordinates  
                           )  
{  
    return 1;   // 屏蔽所有鼠标消息  
}  
// 键盘钩子过程  
LRESULT CALLBACK KeyboardProc(  
                              int code,       // hook code  
                              WPARAM wParam,  // virtual-key code  
                              LPARAM lParam   // keystroke-message information  
                              )  
{  
    // 后门按键用于结束该进程  
    if (VK_F2 == wParam)  
    {  
        ::SendMessage(g_hWnd, WM_CLOSE, 0, 0);  
        UnhookWindowsHookEx(g_hKeyboard);  
        UnhookWindowsHookEx(g_hMouse);  
    }  
    else  
    {  
        return 1;   // 屏蔽所有键盘消息  
    }  
}  
// 安装鼠标钩子过程的函数  
void SetHook(HWND hwnd) // 参数是为了让dll获得调用进程的主窗口的句柄  
{  
    g_hWnd = hwnd;  
    // hook所有进程的鼠标、键盘消息  
    g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, GetModuleHandle("Hook.dll"), 0);  
    g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle("Hook.dll"), 0);  
} [/code]
调用DLL的进程的实现:


/////////////////////////////////////////////////////////////////////////////  
// CHookTestDlg message handlers  
// 导入函数  
__declspec(dllimport) void SetHook(HWND hwnd);  
BOOL CHookTestDlg::OnInitDialog()  
{  
    // TODO: Add extra initialization here  
    // 顶层窗口及最大化窗口的实现  
    int cxScreen, cyScreen;  
    cxScreen = GetSystemMetrics(SM_CXSCREEN);  
    cyScreen = GetSystemMetrics(SM_CYSCREEN);  
    SetWindowPos(&wndTopMost, 0, 0, cxScreen, cyScreen, SWP_SHOWWINDOW);  
    // 调用DLL中的函数  
    SetHook(m_hWnd);  
    return TRUE;  // return TRUE  unless you set the focus to a control  
} [/code]
资料来自:6313814

上面是WH_KEYBOARD
下面是使用WH_KEYBOARD_LL 低级键盘钩子 不需要DLL 直接设置即可

// keyboardhook.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include<iostream>
#include<windows.h>
using namespace std;

HHOOK g_Hook;
LRESULT CALLBACK LowLevelKeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam)
{
        KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *)lParam;
        BOOL bControlKeyDown = 0;
       
    switch (nCode)
        {
        case HC_ACTION:
                {
                        // Check to see if the CTRL key is pressed
                        bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);

                        //Disable CTRL+ESC
                        if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown)
                                return 1;
                        if(wParam == WM_KEYUP)
                                printf("%c", pkbhs->vkCode);

                        break;
                }
        }
        return CallNextHookEx(g_Hook, nCode, wParam, lParam); //回调
        return 1;
}


int _tmain(int argc, _TCHAR* argv[])
{
        MSG msg;
        g_Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL,
                (HOOKPROC)LowLevelKeyboardProc, GetModuleHandleW(0),0);
        while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
        return 0;
}
[/code]
低级鼠标钩子实例:


// mousehook.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include<iostream>
#include<windows.h>
using namespace std;

/* LPARAM type
typedef struct tagMSLLHOOKSTRUCT {
  POINT     pt;
  DWORD     mouseData;
  DWORD     flags;
  DWORD     time;
  ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT;
*/



LRESULT CALLBACK LowLevelMouseProc(
                                                                   int nCode,
                                                                   WPARAM wParam,
                                                                   LPARAM lParam
                                                                   )
{
        if(nCode==HC_ACTION)
        {
                if(wParam==WM_LBUTTONDOWN)
                {
                        return 1;
                }
        }
        return CallNextHookEx(0,nCode,wParam,lParam);
}

int _tmain(int argc, _TCHAR* argv[])
{
        MSG msg;
        SetWindowsHookExW(WH_MOUSE_LL,LowLevelMouseProc,GetModuleHandleW(0),0);
        while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
        return 0;
}
[/code]
QQ安全密码框的全局钩子

1,WH_DEBUG , WH_KEYBOARD_LL, WH_MOUSE_LL
2, WH_DEBUG> WH_KEYBOARD_LL> WH_KEYBOARD
3,后加载的先获得消息并执行
4,QQ定时UNHOOK和HOOK上面3个钩子,保证自己最后被安装,自然就是先取得正确的按键信息,然后阻止这个 消息继续传递下来给别人,就算传下去交给别人,也要修改按键信息,传一个错误的下去



-----------------------------------------------------------------------------------------------------------------------------------------
在下钩子的时候可能我们需要用到通信 可以使用映射,管道,
其实还有一种方便的,就是PE共享节
放到共享节里面的变量时是同实例可以访问的 一般用到多开通信 多开检测,全局dll钩子

#pragma data_seg (".shared")
ULONG g_ulNum;
#pragma data_seg ()
#pragma comment(linker,"/SECTION:.shared,RWS") [/code]RWS:读/写/共享
共享段里的变量可供进程的多个实例访问
普通的全局变量,只对一个实例有效

也可以实现进程通信



将里面的变量extern 在将所在的头文件引用进来 也可以实现通信

详见
hookSpy InjectEx SetWindowHook
LibSpy CreateRemoteThread LoadLibrary
WinSpy CreateRemoteThread WriteProcessMemory

详见:38480141
------------------------------------------------------------------------------------------------------------------------------------------------
DLL注入
分为两种:

1.直接把dll注入目标进程
2.直接把代码注入目标进程
直接注入DLL:
AddDebugPrivilege(void)
OpenProcess()
VirtualAllocEx()
WriteProcessMemory()
CreateRemoteThread()



直接注入代码:
static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
…..
…..
}
AddDebugPrivilege(void)
OpenProcess()
VirtualAllocEx()
WriteProcessMemory()
CreateRemoteThread();



Debug权限与进程打开


BOOL AddDebugPrivilege(void)
{

TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE hToken;

if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
{
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid=luid;
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
if(!OpenProcessToken(GetCurrentProcess(),
                 TOKEN_ADJUST_PRIVILEGES,&hToken))
{
return FALSE;
}
if(!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{
return FALSE;
}
return TRUE;
}

HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD |
                    PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE  |
                    PROCESS_VM_READ,FALSE, PID);
[/code]
其实并不需要这么多函数 但一下函数只能使用在发布版中


typedef long (*RTLADJUSTPRIVILEGE)(ULONG,ULONG,ULONG,PVOID);
RTLADJUSTPRIVILEGE RtlAdjustPrivilege;
RtlAdjustPrivilege=(RTLADJUSTPRIVILEGE)GetProcAddress(LoadLibraryW(L"ntdll.dll"),"RtlAdjustPrivilege");
RtlAdjustPrivilege(20,1,0,&dwRetVal);//debug
RtlAdjustPrivilege(19,1,0,&dwRetVal);[/code]
这样就可以了

直接注入DLL文件

1。打开目标进程
2。获取待注入的DLL路径,分配一块目标进程内的内存,将路径拷贝到该内存中
3。获取kernel32中的LoadLibraryA地址
4。调用CreateRemoteThread,在目标进程中执行loadlibrary + DLL的动作
5。DLL中的DLLMAIN执行
6。释放分配的目标进程中的内存
7。获取kernel32中的FreeLibrary地址
8。调用CreateRemoteThread,在目标进程中执行FreeLibrary + DLL的动作



int InjectDll( HANDLE hProcess, TCHAR* szLibPath)
{
<span style="white-space:pre">        </span>HANDLE hThread;
<span style="white-space:pre">        </span>void*  pLibRemote = 0;
<span style="white-space:pre">        </span>DWORD  hLibModule = 0;
<span style="white-space:pre">        </span>HMODULE hKernel32 = ::GetModuleHandle(_T("Kernel32"));


<span style="white-space:pre">        </span>LPTHREAD_START_ROUTINE pLoadFunc = NULL;


<span style="white-space:pre">        </span>pLoadFunc = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryW");


<span style="white-space:pre">        </span>if (szLibPath == NULL ||
<span style="white-space:pre">                </span>hProcess == NULL ||
<span style="white-space:pre">                </span>pLoadFunc == NULL)
<span style="white-space:pre">        </span>{
<span style="white-space:pre">                </span>return FALSE;
<span style="white-space:pre">        </span>}
<span style="white-space:pre">        </span>pLibRemote = ::VirtualAllocEx( hProcess, NULL, (_tcslen(szLibPath) + 1)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );
<span style="white-space:pre">        </span>if( pLibRemote == NULL )
<span style="white-space:pre">                </span>return false;
<span style="white-space:pre">        </span>::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,(_tcslen(szLibPath) + 1)*sizeof(TCHAR),NULL);


<span style="white-space:pre">        </span>hThread = ::CreateRemoteThread( hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pLoadFunc, 
<span style="white-space:pre">                </span>pLibRemote, 0, NULL );
<span style="white-space:pre">        </span>if( hThread == NULL )
<span style="white-space:pre">                </span>goto JUMP;
<span style="white-space:pre">        </span>DWORD dwError = GetLastError();
<span style="white-space:pre">        </span>::WaitForSingleObject( hThread, INFINITE );
<span style="white-space:pre">        </span>dwError = GetLastError();
<span style="white-space:pre">        </span>::GetExitCodeThread( hThread, &hLibModule );


<span style="white-space:pre">        </span>::CloseHandle( hThread );


JUMP:<span style="white-space:pre">        </span>
<span style="white-space:pre">        </span>::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
<span style="white-space:pre">        </span>if( hLibModule == NULL )
<span style="white-space:pre">                </span>return false;
<span style="white-space:pre">        </span>return hLibModule;
}
[/code]
我改进了下 直接使用PID ,虽然方便了点,但我自己也不推荐使用

//向目标进程写入DLL名称,和LoadLibraryW / A 然后通过CreateRemoteThread 远程CALL和传参

int InjectDll( DWORD PID, TCHAR* szLibPath)
{
        HANDLE hThread;
        void*  pLibRemote = 0;
        DWORD  hLibModule = 0;
        HMODULE hKernel32 = ::GetModuleHandle(_T("Kernel32"));

        LPTHREAD_START_ROUTINE pLoadFunc = NULL;

        pLoadFunc = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hKernel32,"LoadLibraryW");

        HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD |
                    PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE  |
                    PROCESS_VM_READ,FALSE, PID);//这个可以拿出去

        if (szLibPath == NULL ||
                hProcess == NULL ||
                pLoadFunc == NULL)
        {
                return FALSE;
        }
        pLibRemote = ::VirtualAllocEx( hProcess, NULL, (_tcslen(szLibPath) + 1)*sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE );
        if( pLibRemote == NULL )
                return false;
        ::WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath,(_tcslen(szLibPath) + 1)*sizeof(TCHAR),NULL);

        hThread = ::CreateRemoteThread( hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pLoadFunc,
                pLibRemote, 0, NULL );
        if( hThread == NULL )
                goto JUMP;
        DWORD dwError = GetLastError();
        ::WaitForSingleObject( hThread, INFINITE );
        dwError = GetLastError();
        ::GetExitCodeThread( hThread, &hLibModule );

        ::CloseHandle( hThread );

JUMP:       
        ::VirtualFreeEx( hProcess, pLibRemote, sizeof(szLibPath), MEM_RELEASE );
        if( hLibModule == NULL )
                return false;
        return hLibModule;
}[/code]
//注入程序关键代码
UpdateData(TRUE);
InjectDll(m_edit,_T("MyDll.dll"));[/code]DLL普通的而已


直接注入代码:
实现线程函数
static DWORD WINAPI ThreadFunc (PVOID *pData)
{
......some code
}
static void AfterThreadFunc (void)
{
}
打开目标进程(debug权限)
在目标进程内分配pCodeRemote和pDataRemote并将内容拷贝进去//一个是代码 一个是参数
CreateRemoteThread()启动线程执行
从pDataRemote中拿到结果数据
释放pDataRemote和pCodeRemote


声明AfterTheadFunc的原因是获取ThreadFunc函数的长度
代码:向目标写入函数code,和参数

void InjCode (HANDLE hProcess)
{       
        INJDATA        *pDataRemote;
        DWORD        *pCodeRemote;
        HANDLE        hThread = NULL;
        DWORD        dwThreadId = 0;
         DWORD                   dwNumBytesXferred = 0;
               
        pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT,
                        PAGE_READWRITE );
        WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );
        const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc);
        pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT,
                        PAGE_EXECUTE_READWRITE );       
        WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
        hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) pCodeRemote,
                        pDataRemote, 0 , &dwThreadId);
        WaitForSingleObject(hThread, INFINITE);
        ReadProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred);
        //需要判断pDataRemote,pCodeRemote,hThread的有效性
        VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );
        VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE );
        CloseHandle(hThread);                       

}
[/code]
例子:WinSpy


#include <Windows.h>
#include "InjCode.h"

//---------------------------------------------------------------------
// INJDATA
// Notice: The data structure being injected.
//
typedef LRESULT                (WINAPI *SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM);

typedef struct {
        HWND        hwnd;
        SENDMESSAGE                fnSendMessage;        // pointer to user32!SendMessage

        BYTE        pbText[128 * sizeof(TCHAR)];
} INJDATA, *PINJDATA;


//---------------------------------------------------------------------
// ThreadFunc
// Notice: - the code being injected;
//                   - the remote copy of this function retrieves the password;
//
//        Return value: password length
//
static DWORD WINAPI ThreadFunc (INJDATA *pData)
{
        // There must be less than a page-worth of local
        // variables used in this function.

        int        nXferred         = 0;        // number of chars retrieved by WM_GETTEXT

        // Get password
        nXferred = pData->fnSendMessage( pData->hwnd, WM_GETTEXT,
                                                         sizeof(pData->pbText)/sizeof(TCHAR),
                                                         (LPARAM)pData->pbText );
        pData->pbText [127 * sizeof(TCHAR)] = __TEXT('\0');       

        // The thread's exit code is the number
        // of characters retrieved by WM_GETTEXT
        return nXferred;
}

// This function marks the memory address after ThreadFunc.
// int cbCodeSize = (PBYTE) AfterThreadFunc - (PBYTE) ThreadFunc.
static void AfterThreadFunc (void) {
}


//---------------------------------------------------------------------
// GetTextRemote
// Notice: - copies ThreadFunc and INJDATA to the remote process;
//                   - starts the excecution of the remote ThreadFunc;
//
//        Return value: password length;
//
int GetTextRemote (HANDLE hProcess, HWND hWnd, BYTE* pbString, bool fUnicode)
{       
        HINSTANCE        hUser32;
        INJDATA                *pDataRemote;        // the address (in the remote process) where INJDATA will be copied to;
        DWORD                *pCodeRemote;        // the address (in the remote process) where ThreadFunc will be copied to;
        HANDLE                hThread = NULL; // the handle to the thread executing the remote copy of ThreadFunc;
        DWORD                dwThreadId = 0;

        int                  nCharsXferred = 0; // number of chars retrieved by WM_GETTEXT in the remote thread;
        DWORD dwNumBytesXferred = 0; // number of bytes written/read to/from the remote process;
       
        __try {
                hUser32 = GetModuleHandle(__TEXT("user32"));
                if (hUser32 == NULL)
                        __leave;

                // Initialize INJDATA and then
                // copy it to the remote process
                INJDATA DataLocal = {
                        hWnd,
                        (SENDMESSAGE) GetProcAddress(hUser32, fUnicode ? "SendMessageW" : "SendMessageA")                       
                };
       
                if( DataLocal.fnSendMessage == NULL )
                        __leave;               
               
                // 1. Allocate memory in the remote process for INJDATA
                // 2. Write a copy of DataLocal to the allocated memory
                pDataRemote = (INJDATA*) VirtualAllocEx( hProcess, 0, sizeof(INJDATA), MEM_COMMIT, PAGE_READWRITE );
                if (pDataRemote == NULL)
                        __leave;
                WriteProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred );


                // Calculate the number of bytes that ThreadFunc occupies
                const int cbCodeSize = ((LPBYTE) AfterThreadFunc - (LPBYTE) ThreadFunc);

                // 1. Allocate memory in the remote process for the injected ThreadFunc
                // 2. Write a copy of ThreadFunc to the allocated memory
                pCodeRemote = (PDWORD) VirtualAllocEx( hProcess, 0, cbCodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE );               
                if (pCodeRemote == NULL)
                        __leave;
                WriteProcessMemory( hProcess, pCodeRemote, &ThreadFunc, cbCodeSize, &dwNumBytesXferred );
               

                // Start execution of remote ThreadFunc
                hThread = CreateRemoteThread(hProcess, NULL, 0,
                                (LPTHREAD_START_ROUTINE) pCodeRemote,
                                pDataRemote, 0 , &dwThreadId);
                if (hThread == NULL)
                        __leave;

                WaitForSingleObject(hThread, INFINITE);

                // Get result (password) back
                ReadProcessMemory( hProcess, pDataRemote, &DataLocal, sizeof(INJDATA), &dwNumBytesXferred);

                if (fUnicode)  wcscpy((LPWSTR) pbString, (LPCWSTR) DataLocal.pbText);
                else                   strcpy((LPSTR)  pbString, (LPCSTR)  DataLocal.pbText);
        }
        __finally {
                if ( pDataRemote != 0 )
                        VirtualFreeEx( hProcess, pDataRemote, 0, MEM_RELEASE );

                if ( pCodeRemote != 0 )
                        VirtualFreeEx( hProcess, pCodeRemote, 0, MEM_RELEASE );

                if ( hThread != NULL ) {
                        GetExitCodeThread(hThread, (PDWORD) &nCharsXferred);
                        CloseHandle(hThread);                       
                }
        }

        // Return the number of chars retrieved
        // by WM_GETTEXT in the remote thread.
        return nCharsXferred;
}

///////////////////////////////////////////////////////////////////////////

int GetWindowTextRemoteA (HANDLE hProcess, HWND hWnd, LPSTR         lpString)
{
        return GetTextRemote (hProcess, hWnd, (BYTE*)lpString, false);
}

int GetWindowTextRemoteW (HANDLE hProcess, HWND hWnd, LPWSTR lpString)
{
        return GetTextRemote (hProcess, hWnd, (BYTE*)lpString, true);
}

//////////////////////// End Of File //////////////////////////////////////[/code]

获取数据就用ReadProcessMemory





备忘:
hookSpy InjectEx SetWindowHook


LibSpy CreateRemoteThread LoadLibrary


WinSpy CreateRemoteThread WriteProcessMemory
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 19:27

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表