堆 栈 虚拟内存 物理内存的关系

一,背景

自己发现做开发这么年,竟然不是很清楚,然后查了一下资料,根据自己理解总结了一下

二,概述

windows上面物理内存通过页管理【方便物理内存管理,后面堆也是内存管理的算法,只是他依赖虚拟内存】,每一页大小是4K【跟系统有关】

栈是连续内存块,每个线程都一个固定大小栈【1M】,所以我们在函数里面不要数组设置很多,不然就会栈溢出了。c/c++ 可以在vs里面进行设置,其他应该也可以。地址连续为提高内存的访问速度,他的内存管理也非常简单,我们OD或者其他调试工具的时候就会看这个东西,这个无法程序直接体现,除非你自己写汇编语言。栈溢出常常用来远程溢出,以前的strcpy等等函数都没有检测原始数据大小,按照0为结束符号,导致覆盖原来调用压入的运行地址,从而跳转指定的恶意代码,现在基本都换高级语言,很少应用有这个bug。

堆对应程序员语言的new或者malloc(C语言),windows它本质调用HeapAlloc,delete调用FreeHeap,你进入汇编就能看的到。堆内存我认为只是虚拟内存管理小内存的一种算法,他内部分配内存应该也只是虚拟内存(网上是说这么说的),我自己测试时候你分配3000字节的内存,他分配的实际的内存是4K,走的还是虚拟内存分页管理逻辑,从我们开发角度来说,代码基本都是分层,上一层依赖下一层,如果直接操作物理内存,那么怎么标记这块内存已经使用了。

虚拟内存是页管理中对象,我们访问虚拟地址,从而系统要我们访问实际物理内存。我们无法实际操作物理内存,我们操作别的进程内存,可以通过虚拟内存函数进行操作。

下面是window任务管理对应的关系,我们查内存泄漏最好看提交大小,而不是专用内存,因为专有内存可能放的磁盘上面去,那么实际用的物理偏小,但你的程序new的对象确实比物理多很多,程序内存泄漏应该看虚拟内存,而不是实际内存。

c# 打开浏览器商用代码

一,背景

这个需求看起来不复杂,但考虑通用话比较麻烦,一些用户还是用的win7,各种魔改版本。导致各种问题,通过一段时间测试,自己整理出来代码比较通用,可以处理各种用户情况。

二,代码

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Browser
{
    class BrowserHelperV2
    {
        public void Open(string url)
        {
            //微软edge最新浏览器 google浏览器 360极速版本 360安全浏览器 火狐浏览器 默认浏览器
            //循序自己调整,建议explorer 放在最后,最后用默认方式
            //其他浏览器的执行,可以自己添加
            //不一定成功,根据自己测试,只要注册表正常安装是没有什么问题的
            string[] browserNameList = { "msedge.exe", "chrome.exe", "360chrome.exe", "360se.exe", "firefox.exe" };
            processUrl(ref url);
            foreach (var name in browserNameList)
            {
                bool ret = OpenBrowser(url, name);
                if (ret)
                {
                    return;
                }
            }

            //默认浏览器
            OpenDefaultBrowser(url);
        }

        private bool OpenBrowser(string url, string name)
        {
            ProcessStartInfo startInfo = new ProcessStartInfo();
            try
            {
                startInfo.FileName = name;
                startInfo.Arguments = url;
                Process.Start(startInfo);
                return true;
            }
            catch (Exception e)
            {
                Debug.WriteLine("打开异常:" + e.Message);
            }

            return false;
        }

        private bool OpenDefaultBrowser(string url)
        {
            try
            {
                //要引入1.2的版本,网上单独下载,但微软官方没有找到有为什么不用1.0的
                Shell32.Shell shell = new Shell32.Shell();
                shell.Open(url);
                return true;
            }
            catch (Exception)
            {
                return OpenBrowser(url, "explorer.exe");
            }
        }

        /// <summary>
        /// 处理URL,防止解析默认浏览器无法解析格式导致问题
        /// </summary>
        /// <param name="url"></param>
        private void processUrl(ref string url)
        {
            if(url.Length > 5)
            {
                var begin_url = url.Substring(0, 5);
                if (!(begin_url.StartsWith("https") || begin_url.StartsWith("http")))
                {
                    url = "http://" + url;
                }
            }  
        }
    }
}

三,逻辑

先遍历主流的浏览器,一般情况是可以的,不需要完整路径,可以打开。如果打不开,就使用默认浏览器打开,我直接用window shell 打开的,这种比较通用,为什么不用explorer打开一个浏览器,因为他多开一个explorer,这样子感觉体验不是那么好。

内存加载PE技术研究

一,背景

最近研究内存加载DLL技术,这个技术大概10年前的技术,用搜索引擎可以找到很多资料,我自己按照思路,综合其他各种实现思路,大概弄懂核心思路。

市面开源主流代码:

1:PE加载器,可以加载大部分程序,我测试TIM,微信都是可以,加壳的程序没有测试,代码写的非常专业,

https://github.com/polycone/pe-loader

2:DLL加载器,没有进程信息修改,貌似支持64位。

https://github.com/fancycode/MemoryModule

二,PE核心步骤

  1. 导入表修复
  2. 重定位表修复
  3. 进程信息修复(加载EXE才需要,DLL不需要)

三,疑惑问题?

1:为什么需要修复?

因为我们手动加载到内存,然后跳转到入口地址,开始执行代码,因为代码地址都是写死,每次加载都需要系统自动去修改,但我们手动加载就必须手动修改,所以才有修改导入表和重定位表。

因为我们调用函数和一些全局变量都是死地址,这些死地址记录在重定位表里面,所以我们需要修复他。

导入表记录API的地址,PE文件只记录名字或者序号,系统加载的DLL或者EXE会默认修改导入表的FristThunk(IAT),这里面保存API的地址,我们调用系统API的时候,我们调用的系统API的时候。我们调用导入表call的地址。

int main() {
    MessageBox(0, L"hello world", 0, 0);
    return 0;
}
这个导入表的IAT的地址,这里用IDA逆向,加载前等于INT。

CALL IAT对应变量(变量含有真的地址,我们IAT HOOK时候只要修改这个地址就可以了)

2:对齐

分为内存对齐和文件对齐,PE文件结构很多大小都是安装对应的对齐,PE文件保存了文件数据和内存数据,所以刚开始很容易搞混,说白就是告诉你文件怎么读和内存怎么读而已。因为PE是编译生成好的。

内存对齐:windows中,内存属性的基本单位是页,在32位系统是4KB(1000h),在64位系统中是8kb。
文件对齐:为了提高磁盘利用率,把一个物理扇区作为一个对齐粒度的大小,也就是12字节(200H),这是每个数据段都是200H的整数倍的原因。

为什么需要对齐的原因,性能问题。

3:偏移

所有都是基地址为偏移,内存加载就是内存分配起始地址做偏移

4:什么是导入表?

记录程序用哪些系统的API,同时加载后会被系统初始化,提供系统API的真正的地址,要软件能正常调用

资料:https://blog.csdn.net/Apollon_krj/article/details/77417063

5:什么是重定位表?

记录生成EXE或者DLL 函数死地址,如果重定向,就需要进行修改,默认是系统修改。但内存加载必须手动修改。

6:为什么会要重定向?

这种情况基本出现DLL,exe感觉永远不会,他是第一个模块加载,可以优先选位置,这个就好比我们小时候选读书的位置一样,每个都有选位置权利,我们默认可能都是最好一排,但如果我们的位置已经被人选择了,那么我们就只能选择其他的位置。我们编译程序默认按照最好位置涉及,一旦你的位置改变了,那么所有地址都需要更新。

7:为什么进程修复?(只针对EXE的情况)

我们加载的EXE,其实相当于一个新的模块,系统默认不知道的,所以当我们程序获取模块信息会获取不到或者错误,导致逻辑错乱。程序运行不了。如果不进行进程修复,MFC程序不可以内存直接运行的话,因为调用GetMoudleFileName 会获取为空。因为传入hinstance是我们假的地址,这个时候只要我们修改peb的里面模块List 基地址和peb的模块地址就可以了,改成内存new的地址。代码可以借鉴PE-LOADER。

这里PE-loader还对的一些进行hook

命令hook,传递参数,DLL可以直接调用的,可以传入保留那个字段为参数即可,因为PEloader 只针对 exe执行程序,不是针对dll,所以代码没有考虑,哪些需要修复可以通过逆向找到

8:以前人怎么想这个思路?

1:推想+逆向,函数+变量就可以做任何事情,远程注入代码逻辑,分配内测然后注入代码,就可以直接执行,但没有注入DLL舒服,内存加载DLL是为了隐藏DLL,这个好处有很多,防止报毒和加大别人分析代码难度。

2:通过微软的文档,知道系统大概逻辑,我猜测PE-loader就很类似这种,因为他的函数命名就是跟微软底层API命名一样。

9:官网文档?

介绍系统加载DLL的逻辑

https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_data_directory

PE 格式 微软资料

https://docs.microsoft.com/en-us/windows/win32/debug/pe-format

四:总结

围观:学习PE内存加载知识,熟悉PE结构

宏观:优化解决问题能力,怎么通过一个知识点,然后找到对应解决方案,然后通过分析了解,找到一个成熟的解决方案

我自己代码后面再贴,目前有好多日志,主要为了学习用途。

window defender 自带杀毒软件添加白名单

一,背景

我们很多工具类软件,为了防止破解会进行加壳,这些软件如果没有数字签名就会报毒,所以我们有的时候为了使用,所以必须加入白名单,不用每次更新都手动操作一下。

二,过程

  1. 依次转到“开始”菜单  >“设置” >“更新和安全” >“Windows 安全中心”>“病毒和威胁防护”。
  2. 在“病毒和威胁防护”设置下,选择“管理设置”,然后在“排除项”下选择“添加或删除排除项”。 
  3. 选择“添加排除项”,然后选择相应的文件、文件夹、文件类型或进程。排除项也会应用到文件夹内的子文件夹。

window远程桌面大全

微软自身提供客户端连接,我们自己可以下载,手机端挺好用的,如果远程电脑同一个网络是最好的选择,如果你是内网,那么用向日葵即可

https://docs.microsoft.com/zh-cn/azure/virtual-desktop/
https://remotedesktop.uservoice.com/

windows android 远程桌面 app ,方便不能使用google 应用商店的人

链接:https://pan.baidu.com/s/1DhOe3meqdjcW7PKqH4DrtQ
提取码:svqx
复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V5的分享

SendMessage WM_COPYDATA 拒绝错误

背景

SendMessage WM_COPYDATA 我们经常用来进程通信,今天突然改了一下代码加载方式,突然发现消息无法通信,我不断的通过打印日志来确定问题,最终觉得自己代码没有问题,但就是无法发送消息到另外一个进程。突然想到GetLastError() 看一下有什么错误,通过打印发现出现错误5,然后通过vs 带的错误查询,发现是拒绝错误。

解决方案

通过GetLastError, 我的脑海大概猜测是权限问题,于是搜索SendMessage WM_COPYDATA 拒绝错误,然后我找到这篇 https://blog.csdn.net/aa1991/article/details/19504557 ,固然验证是权限问题。如果是按照文章调用 ChangeWindowMessageFilter(WM_COPYDATA, 1); 就可以了

总结

排错需要更加系统化,尽可能了解不同知识点,更重要是思考方式,学会不断调节

贴边程序思路

我们有时候需要实现贴边qq或者微信窗口或者其他窗口的功能,最近研究了一下,大概2个思路。

  • 直接用 GetForegroundWindow ,获取当前前台的窗口句柄,然后获取是否自己想贴边的程序,可以通过类名或者窗口标题和进程名来判断
  • 通过窗口钩子,捕捉窗口移动的消息和一些其他消息来处理

我选择的第一种方式,因为实现起来最简单,启动一个定时器不停检测当前窗口就可以了,如果用钩子,可能被杀毒软件报警,同时代码复杂度会偏高。