/logo.png

Focus in crafting 2022

一种枚举系统热键的思路及代码实现(Win7&Win10)

文章发布至看雪《一种枚举系统热键的思路及代码实现(Win7&Win10)》 前言 现在使用全局快捷键的软件越来越多,经常遇到快捷键被占用的情况,想找出被谁占用了,网上找了一些工具,不过都不支持新版本的Win10。于是自己写了一个(支持Win7到最新的Win10 2004 32/64位,XP就不考虑了),本文顺带记录一下分析思路。 思路分析 说明:Win7/8和Win10的热键数据结构基本一致,本文以Win10 1903 x64作为分析对象,重点是在Hash表的搜索方法上。 众所周知,注册热键需要调用RegisterHotKey,首先看一下函数原型: BOOL RegisterHotKey( HWND hWnd, int id, UINT fsModifiers, UINT vk ); hWnd 窗口句柄 id 热键ID fsModifiers 控制位,如Ctrl/Alt/Shift… vk 虚拟键码 Virtual Key Codes 简单跟一下RegisterHotKey函数,到ntdll!NtUserRegisterHotKey,看一下NtUserRegisterHotKey函数原型: BOOL APIENTRY NtUserRegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk ); 可以看到Native的参数和上层API一致,往下则是Shadow SSDT,进入win32k,Win7/Win8/8.1还是win32k.sys,Win10已拆分成win32k/win32kfull/win32kbase三个模块,其中NtUserRegisterHotKey是win32kfull的导出函数。 打开IDA,定位到NtUserRegisterHotKey函数,其调用RegisterHotKey如下: mov r9d, edi mov dword ptr [rsp+48h+BugCheckParameter2], ebp ; BugCheckParameter2 mov r8d, r14d xor edx, edx mov rcx, rax ; struct tagWND * call _RegisterHotKey IDA推导的参数显示有问题,跟一下参数来源,不难知道RegisterHotKey参数1是hWnd,参数2是NULL,参数3是id,参数4是fsModifiers,参数5是vk。

FastStone Image Viewer注册算法分析+KeyGen

文章发布至看雪《FastStone Image Viewer注册算法分析+KeyGen》 前言 FastStone Image Viewer是一款老牌看图软件,附带编辑/转换图片功能,软件针对个人用户免费,适用于Windows,官方下载:https://www.faststone.org/FSViewerDetail.htm 出于兴趣研究,本文以最新版本v7.5为例,使用IDA和Windbg分析注册算法并实现KeyGen。:) 找验证点 首先查看区段/导入表比较完整,看上去没加壳,资源发现RCData,可能是Delphi/BC++开发。PE头里DllCharacteristics是0(无IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE),不支持ASLR(后面用IDA/Windbg不用ReBase,直接定位,方便分析)。 接下来开始分析注册码判断方式,本文从输入框跟踪用户名引用入手(以前写的《AudioSrv音频服务故障》有说如何找窗口处理过程)。首先运行程序到注册窗口,Windbg附加,输入假码,查看栈回溯。观察之后没有太明显的地方,查看注册框Edit句柄,bp GetWindowTextW条件断点未断下,随后bp NtUserMessageCall拦截WM_GETTEXT,断点命中,查看对应参数获取到用户名,ba r1下内存访问断点,跟踪用户名拷贝,尝试设置多次断点验证,最后定位到关键函数sub_72F248。 消息参数: 0x000D (13) WM_GETTEXT 函数原型: NtStatus (*NtUserMessageCall)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOLEAN bAnsi); 调试前注意函数调用约定,EAX=param1,EDX=param2,ECX=param3,其它参数栈传递。(ADC) https://en.wikipedia.org/wiki/X86_calling_conventions#cite_note-14 算法分析 IDA加载完毕,Shift+F5打开signature,应用bcb5rt(CBuilder 5 runtime),识别到3000多个函数。sub_72F248函数代码如下: CODE:0072F282 call @Controls@TControl@GetText$qqrv ; Controls::TControl::GetText(void) CODE:0072F287 mov eax, [ebp+var_18] CODE:0072F28A lea edx, [ebp+name] ; 用户名 CODE:0072F28D call @Sysutils@Trim$qqrx17System@AnsiString ; Sysutils::Trim(System::AnsiString) CODE:0072F292 lea edx, [ebp+var_20] CODE:0072F295 mov eax, [esi+308h] CODE:0072F29B call @Controls@TControl@GetText$qqrv ; Controls::TControl::GetText(void) CODE:0072F2A0 mov eax, [ebp+var_20] CODE:0072F2A3 lea edx, [ebp+var_1C] CODE:0072F2A6 call @Sysutils@Trim$qqrx17System@AnsiString ; Sysutils::Trim(System::AnsiString) CODE:0072F2AB mov eax, [ebp+var_1C] ; 注册码 CODE:0072F2AE lea edx, [ebp+regcode] CODE:0072F2B1 call @Sysutils@UpperCase$qqrx17System@AnsiString ; Sysutils::UpperCase(System::AnsiString) CODE:0072F2B6 lea eax, [ebp+var_10] ; 字符串变量 = '' clear CODE:0072F2B9 call @System@@LStrClr$qqrr17System@AnsiString ; System::__linkproc__ LStrClr(System::AnsiString &) CODE:0072F2BE mov eax, [ebp+regcode] CODE:0072F2C1 call strlen ; CBuilder 5 runtime .

IoT实践--电脑远程开关的制作

看雪链接:https://bbs.pediy.com/thread-257373.htm 前言 想远程家里电脑,又不想一直开着浪费电。试过WOL(局域网唤醒)的方案不太靠谱,一来唤醒可能会失败,二来电脑如果蓝屏/卡机没法强制关机。于是想到了单片机来控制,至于控制部分,考虑过机械臂,但成本太高,通过步进电机制作又略显麻烦。后面想到了个简单的方案,通过短接PWR-SW开机键两端,产生开机触发信号即可模拟开机动作。所以就有了本文这个东西,文章写得有些琐碎,留个纪念吧。 硬件部分 硬件属于本文重点,虽然原理比较简单,但相对软件,需要准备的东西较多,都可以在X宝买,有些商家为了堆销量1块钱都包邮。 基本原理 STM32板子利用ESP8266模块的WiFi功能连接路由(和Web服务端处于同一个内网),然后定时轮询Web服务器,获取指令(开机/关机、强制关机),得到指令后STM32板子操作GPIO,控制继电器开闭,从而控制PWR-SW开机键闭合。 硬件准备 MCU:STM32F030F4 Cortex-M0入门级,¥6块多。之前用的F103开发板,后面觉得功耗较高、功能过剩,就买了一块F0最小系统。(还不是因为穷)。 继电器:1路5v光耦隔离的即可。 WiFi模块:ESP8266-01s(出厂一般都是刷了固件的,我之前用Arduino把固件写坏了,后面重刷了一次,也顺带升级了版本) USB转UART下载器(可选):可用USART烧录程序。 JLink仿真器(可选):支持SWD,可用SWD烧录程序。 杜邦线:公对公/公对母/母对母若干根。 烙铁、助焊剂(焊膏/松香)、焊锡备用。 热缩管:包扎飞线和杜邦线的接线处。 飞线:接电脑开机键两端。 电路接线 拆下电脑前端面板,用飞线连接开机键两端(无需焊接,捆住固定即可)。飞线出来的两端连接到继电器(可通过杜邦线间接连接)。 买到的STM32F030F4板子有两块引脚排针,需要自己焊上去,当然你也可以买焊好的。 板子需要5v Micro USB电源线,可用普通充电头(我是直接用的电脑USB口,关机状态下提供电源,需要在BIOS里设置) 板子PA1连接到继电器作为电平输入,同时连接5V引脚和共地。 JLink接线(查看JLink接线),UART接线按常规连接TX/RX/GND即可。 ESP8266的TX和RX分别连接PA9和PA10,同时连接3.3V引脚和共地,PA0连接RST用于复位。模块启动时CH-EN引脚默认高电平,因此无需使能。 开发环境 Keil5:例如安装5.29。KeyGen下载 安装STM32F0开发包:Keil.STM32F0xx_DFP.2.0.0.pack,建议用迅雷下载。 配置烧录和调试器:Flash–Configure Flash Tools–Debug–选择JLink,然后设置,没问题的话能SW Device里看到JLink的设备,最后选择Flash Download把STM32F0xx的烧录信息添加进去,例如STM32F0xx 16KB Flash,地址范围0x08000000~(+0x00004000)。然后勾选Reset and Run(下载后运行)。 配置编译,优化选择O1(O0生成的文件超出了Flash的容量)。 代码实现 因为工程比较简单,也写了注释,所以我将代码全部放入main.c中便于阅读。程序首先初始化定时器以及各外设,连接WiFi后开始轮询获取服务端数据,通过解析数据来设置PA1端口的高低电平,进而控制继电器闭合。 初始化定时器 //接收数据定时器 TIM1_Init(50); //接收超时定时器 TIM3_Init(5000); //轮询定时器 TIM14_Init(3000); 初始化ESP8266,控制WiFi void WiFi_Init() { GPIO_InitTypeDef GPIO_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOA, &GPIO_InitStruct); RESET_IO(1); } char WiFi_Start() { //复位 if (WiFi_Reset(50)) { return 1; } //设置STA模式 if (WiFi_SendCmd("AT+CWMODE=1",50)) { return 1; } //取消自动连接 if (WiFi_SendCmd("AT+CWAUTOCONN=0",50)) { return 1; } //开始连接 if (WiFi_Connect(30)){ return 1; } //开启透传 if(WiFi_SendCmd("AT+CIPMODE=1",50)){ return 1; } //关闭多路连接 if(WiFi_SendCmd("AT+CIPMUX=0",50)){ return 1; } return 0; } 初始化USART void USART1_Init(unsigned int baud) { GPIO_InitTypeDef GPIO_InitStruct; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //设置PA9/PA10作为TX/RX端口 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); GPIO_InitStruct.