分类 开发笔记 下的文章

最近研究逆向和汇编的时候常需要在汇编指令和机器码之间进行转换。这种转换的需求有时类似于查表,查那么几个就行。有时候又需要写代码进行大量转换,因此记录一下汇编和机器码之间的多种转换方式,以及他们之间的区别。

在线网站转换

该方式适用于初学汇编,只需要对自己疑惑的指令进行相互转换即可(也可以通过爬虫实现自动化,但不推荐)

Online ARM to HEX Converter (armconverter.com) 能够完成ARM架构的互相转换

1.png

Online Assembler and Disassembler (shell-storm.org) 多架构转换,使用keystone实现(后面会讲)

上述网站均支持大小端选择

IDA 插件 Patching

该项目支持Windows、Linux和macOS,以及x86/x64,arm/arm64,项目开源地址如下:

GitHub - gaasedelen/patching: An Interactive Binary Patching Plugin for IDA Pro

该项目依赖IDA pro 7.6和python3

可以根据需要自行安装,也可以下载我的安装好patching的IDA Pro

https://pan.baidu.com/s/1YzTcmNMdxxCd_fAvhXrOBw?pwd=gdgl

使用方式

使用IDA随意打开一个二进制文件,在汇编窗口选中指令右键,会出现一个assemble选项

2.png

在打开的窗口中可以修改汇编指令,图中的bytes窗口就可以输出相应的机器码,此时按下回车键还可以保存修改到当前的IDA数据库中。只能将汇编转换成机器码。

3.png

Keystone

keystone是个汇编框架,支持windows、linux以及arm、mips、x86等架构,提供C/Python接口。作者的官网和项目主页如下

Keystone – The Ultimate Assembler (keystone-engine.org)

https://github.com/keystone-engine/keystone

安装方式

使用python pip即可

pip install keystone
pip install keystone-engine

使用方式

from keystone import *

ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
code = 'ADD W8,W8,W16;ADD W9,W9,W10'
encode, count = ks.asm(code)print(encode, count)

上述代码中,ks.asm需要输入一串汇编指令,多条汇编指令之间可用分号;隔开,它有两个返回值:

encode:返回由汇编指令转换来的机器码的一个list

count:返回由汇编指令转换得到的机器码的指令条数

因此上述代码若使用print打印出encode和count,将会得到如下结果

[8, 1, 16, 11, 41, 1, 10, 11] 2

此外,ks是Ks的一个对象,在这里指定目标架构和模式,构造的时候需要传入这两个参数arch和mode,它们实质上是一些整型的全局变量,加起来一共有90个全局变量,根据变量名称能够了解其对应的架构和模式,按照需要传递参数即可。示例为小端序的ARM64。

pwntools

作为CTF比赛中pwn方向最重要的工具,pwntools在其内部pwnlib.asm和pwnlib.disasm封装了汇编和机器码之间互相转换的方式

pwntools的安装方式请自行查询,网上教程很多,但在你使用asm和disasm时可能会出现一些问题,提示没有相关文件或者模块之类的,这是由于该函数依赖于binutils库,需要安装binutils,可参考官方文档进行安装:

Binutils — pwntools 2.2.1 documentation (python3-pwntools.readthedocs.io)

ubuntu下binutils的安装方式

apt-get install software-properties-common
apt-add-repository ppa:pwntools/binutils
apt-get update

apt-get install binutils-$ARCH-linux-gnu

其中$ARCH改为你希望适用的目标架构即可

使用方式

from pwn import *

context.arch = 'i386'
print(asm("mov eax,ebx"))
print(disasm(p32(0xd889)))

以上就能将‘mov eax,ebx’和d8 89在i386架构下进行转换,contex.arch注明的是整个脚本中的架构,此外还可以使用context.os来指明操作系统。

如果需要在一条语句中使用另一种架构,可以通过在asm函数中指明arch的方式进行,就像这样:asm("mov eax,ebx",arch = 'i386',os = 'linux')

上述代码运行之后的打印结果如下:

b'\x89\xd8'
0:   89 d8                   mov    eax, ebx

需要注意的是,由于大小端序的问题,disasm中传递参数和你看到的机器码的顺序问题。

此外,binutils我没找到能够在windows下安装的方法,因此该方式可能只适用于linux和macOS(尽管pwntools的大部分功能能够在windows下正常运行,但还是建议在linux下使用pwntools)

转自 https://www.cnblogs.com/level5uiharu/p/16910691.html

Anthropic 的 Messages API 更倾向于为开发者提供对复杂推理、长文档处理和高级工具调用的精细控制。OpenAI 的 API 生态则更侧重于简化智能体(Agent)开发流程,并最大化跨提供商的兼容性。

两者的接口设计服务于不同的应用场景。

  • Anthropic Messages API (/v1/messages):专为利用 Claude 的原生能力设计,如扩展思考(Extended Thinking)、提示缓存(Prompt Caching)和计算机使用(Computer Use)。它支持在单个请求中运行服务器端工具。
  • OpenAI Chat Completions API (/v1/chat/completions):作为行业事实标准,设计上无状态,你需要在每次请求中管理完整的对话历史。其最大优势是生态兼容性最广。
  • OpenAI Responses API (/v1/responses):为智能体工作流打造,支持在单次 API 调用中让模型自行编排多个内置工具(如网页搜索、代码解释器)。它还通过 previous_response_id 或服务端对话来管理状态,减少了手动维护历史的负担。

虽然 Anthropic 提供了兼容层,允许你继续使用 OpenAI SDK 来调用 Claude,但这主要是为了便于测试和快速评估,并非生产环境的长期解决方案。

  • 兼容性限制:使用 OpenAI SDK 调用 Claude 时,工具调用的 strict 参数会被忽略,意味着 JSON 输出不保证严格遵循你提供的 Schema。此外,音频输入会被静默忽略,且不支持提示缓存。
  • 系统消息处理:这是最显著的差异之一。OpenAI 允许在对话任意位置放置系统/开发者消息,而 Anthropic 仅支持一条初始系统消息。兼容层会将所有系统消息拼接后置于开头。

两者在高级功能的侧重点上有明显不同。

  • 扩展思考:这是 Anthropic 的强项。你可以通过原生 API 获取 Claude 逐步的详细推理过程(thinking 参数)。而通过 OpenAI SDK 调用时,虽然思考能力生效,但不会返回详细的思考内容。
  • 内置工具:OpenAI 的 Responses API 提供了一站式的内置工具(网页搜索、文件搜索、代码解释器)。Anthropic 也通过服务器工具提供类似能力,但其设计更强调与自有工具链的集成。
  • 提示缓存:Anthropic 原生支持提示缓存,对于重复发送相同上下文的场景(如长文档分析),可大幅降低成本。此功能在 OpenAI SDK 兼容模式下不可用。

根据实际工作负载的不同,两个模型系列展现出不同的倾向。

  • Anthropic 强项:通常在长文档分析、编码任务和需要高一致性的结构化输出方面表现突出,并在企业级支出中占有重要份额。其定价在旗舰层级通常较高,但通过提示缓存(最高可节省约 90% 缓存输入成本)能有效控制长上下文场景的开销。
  • OpenAI 强项:优势在于多模态能力、广泛的生态以及低成本的小模型梯队(如 Nano 系列)。对于高吞吐量的分类和提取任务,成本可能更低。其定价策略通常更具竞争力,旗舰模型价格可能更低,但输出密集型任务的成本仍是考量重点。
  • 如果你需要最大化长文本处理、复杂代码生成、精细的推理过程控制,或者你是企业级用户且工作负载中包含大量重复的上下文,Anthropic 的原生 API 可能更适合你。
  • 如果你在构建通用的聊天应用、多模态应用,或者希望利用最广泛的开发工具和内置的 Agent 能力来快速原型开发,OpenAI 的 API(尤其是 Responses API) 通常是更顺畅的选择。

如下图所示:

  1. 按下 win+s 键
  2. 找到 “基于虚拟化的安全性” 将它关闭

关闭方法:

  1. 搜索 “内核隔离” ,打开窗口后将内存完整性关闭
    2.png
  2. 打开注册表,找到“HKEY_LOCAL_MACHINE/System\CurrentControlSet\Control\DeviceGuard”,选中后双击“EnableVirtualizationBasedSecurity”,将DWORD值设置为0,重启电脑
  3. 重启后正常

最近在尝试使用 Electron 开发桌面端应用。

搭建 Electron 开发环境主要分为两步:先安装 Node.js,再通过脚手架工具创建一个项目模板。

1. 安装前置环境:Node.js

Electron 本身是一个 Node.js 模块,所以必须先安装 Node.js。

  • 下载安装:访问 Node.js 官网下载 LTS(长期支持)版本 的安装包并安装。对于 Windows 用户,也可以使用 winget install OpenJS.NodeJS 命令来安装。
  • 验证:安装完成后,打开终端(命令行),输入以下命令,能显示出版本号即表示成功。

    node -v
    npm -v
注意:Electron 虽然由 Node.js 驱动,但它会打包自己的 Node.js 运行时。这意味着你的最终用户不需要提前安装 Node.js 就能运行你的应用。

2. 创建项目:使用 Electron Forge 脚手架

手动配置 Electron 项目比较繁琐,推荐使用官方维护的脚手架工具 Electron Forge,它能一键生成包含打包工具的基础项目。

在终端中运行以下命令来创建项目(my-app 是你的项目名称,可自定义):

npm create electron-app@latest my-app

运行后,它会交互式地询问你几个配置选项,按推荐选择即可:

  1. Bundler(打包器):建议选 None。这样在集成原生模块时无需额外配置。
  2. Language(语言):选 JavaScript(如果你熟悉 TypeScript 也可以选它)。
  3. Electron Version:选 Latest(最新版)。
  4. Initialize git:按需选择。

3. 运行与开发

进入项目目录并启动应用:

cd my-app
npm start

如果一切顺利,你会看到一个默认的 Electron 窗口弹出,这说明开发环境已经就绪。

4. 网络优化(国内环境)

如果在安装依赖或首次启动(下载 Electron 二进制包)时速度很慢或失败,可以配置国内镜像源。在项目根目录的 .npmrc 文件中添加以下内容:

ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/

5. 基础项目结构

脚手架生成的项目通常包含以下核心文件,了解它们有助于你开始开发:

  • package.json:项目配置,包含 main 入口(通常是 main.js)和 start 脚本。
  • main.js:主进程文件。它管理应用的生命周期、创建窗口,并运行在完整的 Node.js 环境中。
  • index.html:渲染进程的入口页面。所有界面相关的 HTML/CSS/JS 都从这里开始,它本质上是一个浏览器窗口。
  • preload.js(可选):用于在渲染进程和主进程之间安全地暴露 API。

Android 用户是否也想拥有像 iOS 一样在一个页面滑动到完全回退之前就能看到之前的页面的功能呢?

预测性返回(Predictive Back)是 Android 13 引入的手势导航特性。当用户在屏幕边缘执行返回滑动时,当前界面会跟随手势缩小或移动,同时后方界面(或主屏幕)开始显现。用户可以在看到预览后决定是否松开手指完成返回,或反向滑动取消操作。

优势与劣势

优势:
提前预览返回目标,避免因误触边缘而意外退出应用或丢失当前操作状态,可视化的预览让用户明确知道“返回”会去哪里,交互更直观。配合系统动画,跨 Activity、跨任务以及返回主屏幕的过渡更加自然连贯。

劣势:
生态适配不一致是当前最主要的问题。许多第三方应用(如部分版本的 Spotify、Chrome)尚未完全适配,导致部分场景下有预览动画,部分场景下只有传统返回箭头,交互体验割裂。对于不熟悉该特性的用户,同一个返回手势在不同应用中表现不同,可能造成困惑,部分用户因此回流至传统的三键导航。旧版 onBackPressed 和 KEYCODE_BACK 回调在新机制下行为改变,开发者必须迁移至新的 API 才能正确拦截手势。

标准实现代码

最推荐的方式是使用 AndroidX 的向后兼容 API。如果你的项目使用了 Compose,可以直接使用 PredictiveBackHandler;如果是传统 View 体系或需要更底层的控制,则通过 OnBackPressedCallback 配合 OnBackPressedDispatcher。

Jetpack Compose(推荐):
使用 PredictiveBackHandler 可以获取 Flow<BackEventCompat>,实时读取手势进度(progress 值 0~1)来实现自定义动画。

// 确保依赖: androidx.activity:activity-compose:1.8.0+
PredictiveBackHandler(enabled = shouldInterceptBack) { progress: Flow<BackEventCompat> ->
    try {
        progress.collect { backEvent ->
            // 根据 backEvent.progress 更新 UI 动画,例如缩放、位移
            myAnimatable.snapTo(1f - backEvent.progress)
        }
        // 手势完成,执行真正的返回逻辑(如 popBackStack)
        navController.popBackStack()
    } catch (e: CancellationException) {
        // 手势被取消,恢复 UI 状态
        myAnimatable.animateTo(1f)
        throw e
    }
}

传统 View 体系(AndroidX):
核心是使用 OnBackPressedCallback,它会在启用预测性返回的应用中自动获得动画进度回调。

// 1. 依赖: androidx.activity:activity:1.6.0+
// 2. AndroidManifest 中启用(默认通常已启用,可显式声明)
// <application android:enableOnBackInvokedCallback="true" ...>

class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 创建 Callback,仅当需要拦截时才启用
        val callback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                // 执行自定义返回逻辑(如切换 Fragment)
                supportFragmentManager.popBackStack()
            }
            // 如需自定义动画,重写进度相关方法
            // override fun handleOnBackProgressed(backEvent: BackEventCompat) { ... }
            // override fun handleOnBackCancelled() { ... }
        }
        onBackPressedDispatcher.addCallback(this, callback)
    }
}