尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

从Claude额度传输看浮点数逆向:IEEE 754标准与API数据解析实战

从Claude额度传输看浮点数逆向:IEEE 754标准与API数据解析实战 1. 项目概述从一次“意外发现”到系统性探索最近在折腾一些AI服务的API调用时遇到了一个挺有意思的现象。我订阅了Claude的某个服务在它的Web控制台或者客户端里通常会显示一个“剩余额度”或者“使用量”的进度条。出于好奇也是出于程序员的本能我习惯性地打开了浏览器的开发者工具想看看这些数据是怎么从后端传过来的。结果发现这个“额度”数值在传输和前端显示时并不是我们常见的整数或者简单的字符串而是一个浮点数Floating Point Number。这个发现让我心里一动。在很多涉及计费、配额、资源限制的系统里为了安全和防止篡改关键数据往往会在后端进行复杂的计算和签名前端只负责展示。但浮点数本身在计算机内存中的存储格式IEEE 754标准是公开且固定的。如果一个系统的关键业务数据比如剩余额度以原始的浮点数形式传输是否意味着我们有可能通过逆向这个浮点数窥探到一些后端计算的逻辑甚至验证其一致性这听起来有点像在玩一个数字解谜游戏。所以这个项目的核心并不是要去“破解”或“攻击”某个服务——那既不道德也可能违法。而是以一个技术研究者的视角去探索“浮点数”在类似Claude订阅额度这样的业务场景中可能扮演的角色、暴露的信息以及其中蕴含的技术逻辑。我们会从前端抓包开始定位到传输的浮点数字段然后将其从十六进制或十进制表示逆向解析为它在内存中的真实二进制形态再结合IEEE 754标准去理解这个数值的构成。整个过程更像是一次对网络数据传输格式和数值表示原理的深度实践。注意本文所有操作均基于公开、合法的技术研究目的旨在学习计算机科学中浮点数表示、网络协议分析和数据解析技术。严禁将相关技术用于干扰、破坏或未授权访问任何在线服务。请务必遵守相关服务条款和法律法规。2. 核心思路与技术选型为什么是浮点数如何逆向2.1 浮点数作为业务数据传输载体的可能性分析首先我们要问为什么像“剩余额度”这样的数据会用浮点数来传输而不是更直观的整数比如剩余1000次调用精度需求额度可能不是一个整数。例如每次对话消耗的“额度”可能是一个根据Token数量、模型复杂度计算出的带小数的值如0.85、2.33。累计使用量和剩余额度自然也就成了浮点数。计算统一性后端在计算额度时可能全程采用浮点数运算为了保持精度一致直接传递浮点数结果给前端避免整数与浮点数转换带来的精度损失或额外计算。数据压缩与效率相比于传输一个格式化的字符串如“剩余额度95.5%”直接传输一个双精度浮点数8字节可能更节省带宽解析也更快。标准化JSON等通用数据交换格式天然支持number类型而JavaScript中的number就是双精度浮点数。后端如用Python、Java生成一个浮点数序列化为JSON前端JavaScript直接接收并使用链路非常自然。因此在网络请求的响应体Response Body里我们有很大概率会找到一个键值对例如“remaining_quota”: 0.955或者“credit”: 102.4。我们的目标就是找到它。2.2 逆向工程的技术路径设计“逆向”在这里不是指反编译二进制程序而是指从可见的数据表现形式反向推导其生成逻辑或验证其内部状态。我们的路径非常清晰数据捕获使用浏览器开发者工具F12的Network面板捕获与Claude服务交互的XHR/Fetch请求。重点关注返回JSON数据的API。字段定位在响应JSON中寻找与额度、配额、信用、使用量相关的字段。其值通常是一个数字Number。浮点数深度解析获得这个数字后进行以下逆向分析十进制转内存表示将这个十进制浮点数转换为它在计算机内存中按照IEEE 754双精度标准存储的64位二进制形式。拆分三段式根据IEEE 754标准将这64位拆分为符号位1 bit、指数位11 bits、尾数位52 bits。分析含义观察这个浮点数的各个组成部分。指数位是否固定尾数位是否有规律这个浮点数值本身是否与前端显示的进度条百分比有直接的数学关系例如0.955对应95.5%逻辑推测与验证基于对浮点数的分析尝试推测后端的计算逻辑。例如剩余额度是否是总额度 - 已用额度的浮点数结果这个结果是否每次请求都重新计算通过多次请求、触发额度变化观察该浮点数的变化规律可以验证我们的推测。2.3 工具选型精准、高效的瑞士军刀组合工欲善其事必先利其器。针对上述每一步都需要合适的工具数据捕获与分析浏览器开发者工具是首选。Chrome/Firefox/Edge的DevTools功能强大能直接预览JSON、复制响应数据。进阶工具如Burp Suite或Charles可用于更复杂的抓包和重放但对于本项目浏览器工具足够。浮点数转换与计算在线工具搜索“IEEE 754浮点数转换器”、“十六进制浮点数转换”能找到很多可视化工具。它们能直观地进行十进制、十六进制、二进制之间的转换并拆分符号、指数、尾数。这是快速验证和学习的利器。编程语言为了自动化分析和深度探索编程是必须的。Pythonstruct模块的pack和unpack函数可以非常方便地在浮点数和它的字节表示之间转换。numpy库也能提供高精度的浮点运算和查看内存表示。JavaScript由于数据最终在前端处理用JS分析也很有意义。可以利用ArrayBuffer、Float64Array、DataView这些API来操作浮点数的内存表示。C/C对于理解底层内存布局最直接。通过指针和联合体union可以直接查看浮点数每一个字节的内存值。十六进制查看与编辑在分析网络数据包时有时需要看原始的十六进制数据。开发者工具通常有“查看原始响应”的选项。Wireshark是更专业的网络协议分析工具但本项目复杂度用不上。我的选择是以浏览器开发者工具为入口用Python编写核心的分析脚本辅以在线工具进行交叉验证。Python的struct模块完美契合我们的需求代码简洁表达力强。3. 实操过程从抓包到浮点数拆解3.1 第一步捕获网络请求定位关键数据打开Claude的Web界面例如其控制台或使用页面并登录你的账号。按下F12打开开发者工具切换到Network网络面板。在Network面板中勾选“Preserve log”保留日志以防页面跳转时请求记录被清除。刷新页面或者进行一个会触发额度查询的操作比如发送一条消息后查看额度。在Network面板的请求列表中寻找可能包含额度信息的请求。通常这类请求的URL会包含/api/、/usage、/quota、/subscription等关键词。请求方法多为GET。点击目标请求在右侧的“Response”响应或“Preview”预览标签页中查看返回的数据。数据格式大概率是JSON。一个假设的响应数据可能长这样{ subscription_status: active, plan_name: Pro, total_quota: 1000.0, used_quota: 45.5, remaining_quota: 954.5, reset_date: 2023-10-27T00:00:00Z }或者更简洁的{ has_access: true, rate_limit: 0.955 }我们的目标字段就是“remaining_quota”: 954.5或“rate_limit”: 0.955。记下这个数值例如954.5。实操心得有时候额度信息可能嵌套在更深的结构里或者字段名不那么直观如“credit”、“balance”。需要耐心寻找和尝试。另外一些应用可能对API响应做了压缩或编码但现代开发者工具通常能自动解压Gzip并友好地显示JSON。3.2 第二步将浮点数转换为内存字节表示Python实现拿到了十进制浮点数954.5我们现在要用Python看看它在内存里到底是什么样子。核心原理IEEE 754双精度浮点数在内存中占用8个字节64位。我们需要一个方法将这8个字节的二进制或十六进制形式提取出来。方法一使用struct.pack和hexlifyimport struct import binascii # 我们抓取到的剩余额度值 remaining_quota 954.5 # 使用‘d’格式符表示双精度浮点数double # struct.pack 将Python浮点数打包成按照指定格式的字节串 packed_bytes struct.pack(d, remaining_quota) # ‘’表示大端字节序网络传输常用 # 也可以使用‘d’小端序取决于系统但大端序更通用 # 将字节串转换为十六进制字符串便于阅读 hex_representation binascii.hexlify(packed_bytes).decode(utf-8) print(f浮点数 {remaining_quota} 的内存十六进制表示大端: 0x{hex_representation})运行这段代码输出可能是浮点数 954.5 的内存十六进制表示大端: 0x4088dd0000000000方法二使用float.hex()方法Python的浮点数对象自带一个hex()方法可以直接返回其十六进制字符串表示格式符合C语言中%a格式符的规范。hex_from_float remaining_quota.hex() print(f使用 float.hex() 得到的表示: {hex_from_float})输出可能是0x1.dd1a0000000000p9。这种表示法0xh.hhhhp±d是科学计数法的十六进制形式p9表示乘以2的9次方。它和原始的内存字节序表示是等价的但格式不同。对于我们逆向分析内存布局的目的方法一得到的0x4088dd0000000000更直接因为它对应着内存中连续的8个字节。3.3 第三步拆解IEEE 754双精度浮点数现在我们有了64位的十六进制值0x4088dd0000000000。我们把它转换成二进制并按照IEEE 754标准进行拆解。十六进制转二进制0x4088dd0000000000展开为64位二进制每4位十六进制转4位二进制0100 0000 1000 1000 1101 1101 0000 ... 0000中间0省略。拆分三段符号位 S (Sign)第1位最高位。0表示正数。指数位 E (Exponent)接下来的11位第2到第12位。从上面二进制看是100 0000 1000即0x408的二进制部分。尾数位 M (Mantissa/Fraction)剩下的52位第13到第64位。这里是1000 1101 1101 0000 ... 0000。计算真实值 IEEE 754双精度浮点数的值计算公式为V (-1)^S * 2^(E - 1023) * (1 M)E是11位指数位的无符号整数。0x408的十进制是1032。M是52位尾数位表示的小数需要将其解释为二进制小数点在前的数。1000 1101 1101...这部分二进制转换成十进制小数大约是0.138916015625具体计算需将每位除以2的对应次方并累加过程略繁通常由程序完成。代入公式V 1 * 2^(1032-1023) * (1 0.138916015625) 2^9 * 1.138916015625 512 * 1.138916015625 954.5。看我们成功地从内存表示0x4088dd0000000000逆向计算回了954.5。这个过程验证了我们抓取的数据确实是标准的双精度浮点数。实操心得手动计算指数和尾数非常繁琐。在实际分析中我们更关注这个浮点数的“构成特征”。例如对于额度百分比0到1之间其指数位通常会固定在一个较小的范围如1022到1023对应2的-1到0次方尾数位的变化则直接反映了百分比的小数部分。通过编写一个小脚本自动提取并打印S、E、M能极大提高效率。3.4 第四步编写自动化分析脚本为了高效分析多次请求的额度数据我们可以编写一个Python脚本自动完成抓包数据假设已保存为JSON文件的解析和浮点数拆解。import json import struct import binascii def analyze_float(value, name): 分析一个浮点数打印其内存表示和IEEE 754分解 if not isinstance(value, (int, float)): print(f{name} 不是数字类型) return # 1. 打包为字节大端序 packed struct.pack(d, float(value)) hex_repr binascii.hexlify(packed).decode(utf-8) # 2. 将字节转换为整数以便进行位操作 int_repr int.from_bytes(packed, byteorderbig, signedFalse) # 3. 提取符号位、指数位、尾数位 sign_bit (int_repr 63) 0x1 exponent_bits (int_repr 52) 0x7FF # 11位掩码 mantissa_bits int_repr 0xFFFFFFFFFFFFF # 52位掩码 # 4. 计算实际指数减去偏移量1023 actual_exponent exponent_bits - 1023 # 5. 计算尾数值 (1 M/2^52) mantissa_value 1.0 (mantissa_bits / (2**52)) print(f\n 分析字段: {name} ) print(f 十进制值: {value}) print(f 十六进制内存表示 (大端): 0x{hex_repr}) print(f 符号位 S: {sign_bit} ({正数 if sign_bit0 else 负数})) print(f 指数位 E (11位): {exponent_bits} (二进制: {exponent_bits:011b})) print(f 实际指数 (E-1023): {actual_exponent}) print(f 尾数位 M (52位): {mantissa_bits:#x} (...)) print(f 尾数值 (1M): {mantissa_value}) print(f 验证计算: (-1)^{sign_bit} * 2^{actual_exponent} * {mantissa_value} {(-1)**sign_bit * (2**actual_exponent) * mantissa_value}) # 假设我们从网络请求中复制了JSON响应保存为‘response.json’ with open(response.json, r) as f: data json.load(f) # 分析疑似额度的字段 analyze_float(data.get(remaining_quota), remaining_quota) analyze_float(data.get(rate_limit), rate_limit) analyze_float(data.get(used_quota), used_quota) analyze_float(data.get(total_quota), total_quota)运行这个脚本对于954.5你会得到结构化的输出清晰地展示其内存构成。通过对比多次请求额度变化前后的分析结果你可以观察指数和尾数的变化模式。4. 深度解析从浮点数模式推测后端逻辑通过上述方法获取并分析了一系列额度相关的浮点数后我们可以开始做一些有趣的推测和验证。4.1 场景一额度百分比0.0 ~ 1.0如果前端显示的是百分比进度条那么传输的浮点数很可能就是已用额度 / 总额度或剩余额度 / 总额度的结果即一个介于0和1之间的值。特征这类浮点数的指数位会非常固定。因为对于 (0.5, 1.0] 区间的数其IEEE 754表示的实际指数是 -1即2^(-1) 0.5。对应的指数位E 实际指数 1023 1022。例如0.955对应的十六进制可能是0x3fe8e8ba2e8ba2e9。分析其指数位一定是1022十六进制0x3FE的高11位。验证检查你抓取到的rate_limit或类似字段。如果它的值在0到1之间且指数位恒为1022那么基本可以确定它表示一个百分比。尾数位的细微变化就对应了百分比的微小差异。后端逻辑推测后端可能每次请求都实时计算剩余Token数 / 总Token数得到一个双精度浮点数然后直接返回。这个计算可能发生在数据库查询后或者是一个缓存的值。4.2 场景二绝对额度值如Token数如果传输的是像954.5这样的绝对值它代表的是具体的剩余调用次数或Token数。特征指数位会随着数值的大小而变化。954.5的指数位是10320x408因为954.5约等于2^9 * 1.1389。验证同时抓取total_quota(如1000.0)、used_quota(如45.5) 和remaining_quota(如954.5)。验证它们是否符合remaining total - used的浮点数运算关系。注意由于浮点数精度问题1000.0 - 45.5在计算机中计算的结果可能不是精确的954.5而是954.5000000000001之类的极接近值。你需要用abs(a - b) 1e-9这样的方式来判断相等而不是直接。后端逻辑推测实时计算每次API请求都从数据库读取used然后计算total - used并返回。这种情况下remaining值会频繁变化。缓存更新remaining是一个缓存值只在额度被消耗如完成一次对话时更新。在两次消耗之间多次查询API返回的都是同一个缓存值。你可以通过快速连续发送多次查询请求来验证这一点。4.3 场景三编码或哈希的痕迹有时开发者可能会对敏感数据进行简单混淆虽然不加密。例如将额度乘以一个固定系数或者与一个固定值进行异或后再传输。虽然仍是浮点数但值看起来是“随机”的。特征你得到的浮点数值与前端显示的值没有明显的线性关系如不是百分比也不是直观的Token数。例如前端显示95.5%但传输的值是12345.678。逆向尝试如果怀疑是线性变换可以收集两组数据显示值D1传输值V1和D2,V2。假设变换是V a * D b联立方程可以解出a和b。然后用第三组数据验证。重要提醒如果发现复杂的、非线性的变换或者数据看起来完全随机那么它很可能经过了真正的加密或哈希。此时仅通过逆向浮点数格式是无法破解的因为这已经超出了数据表示的范畴进入了密码学领域。请立即停止深度逆向尝试因为这可能触及服务的安全底线。注意事项在进行多次请求以观察数据变化时请务必控制频率避免对服务端造成负载压力触发反爬虫机制。这既是技术道德也是保护自己账号不被封禁的必要措施。5. 常见问题与排查技巧实录在实际操作中你可能会遇到各种各样的问题。下面是我踩过的一些坑和总结的技巧。5.1 问题在Network面板里找不到清晰的JSON响应可能原因1数据被压缩了。查看请求的Response Headers如果有Content-Encoding: gzip或br说明响应体被压缩了。好消息是Chrome等浏览器的开发者工具通常会自动解压并显示在Preview/Response标签页里。如果显示乱码可以尝试点击Response标签页旁的“View source”查看原始字节但通常不需要。可能原因2数据是WebSocket或SSE传输。对于一些实时更新额度的应用可能使用WebSocket或Server-Sent Events (SSE)。这时你需要到开发者工具的“WS”或“其他”类型请求里去找。消息内容可能依然是JSON格式。可能原因3数据通过GraphQL API传输。请求方法可能是POST请求体是一个GraphQL查询语句响应体也是JSON但结构由查询决定。你需要找到查询“额度”的那个GraphQL请求。排查技巧在Network面板使用搜索功能CtrlF。直接搜索关键词如quota、credit、usage、limit、remaining可以快速定位到包含这些字段的请求。5.2 问题找到了数字字段但如何确定它就是我要的“额度”关联验证法进行一个明确会消耗额度的操作如发送一条长消息然后立即刷新或再次查询。观察哪个数字字段发生了减少。那个字段很可能就是剩余额度或已用额度。总和验证法如果同时存在total、used、remaining三个字段验证total ≈ used remaining是否成立考虑浮点误差。UI对照法保持开发者工具打开同时观察网页UI上的额度显示。修改找到的数值字段在开发者工具的Response预览里无法直接改但可以复制值看其是否与UI上的数字或进度条有直接对应关系例如0.955对应95.5%。5.3 问题浮点数计算存在精度误差导致判断相等失败这是浮点数运算的经典问题。# 错误示范 if remaining_quota total_quota - used_quota: # 可能永远不成立 print(匹配) # 正确做法使用一个极小的误差范围epsilon进行比较 epsilon 1e-9 if abs(remaining_quota - (total_quota - used_quota)) epsilon: print(在误差范围内匹配)在编写分析脚本验证假设时务必使用这种方法。5.4 问题使用struct.pack时字节序Endianness应该选大端还是小端网络传输通常使用大端序Big-Endian也称为网络字节序Network Byte Order。这是为了在不同架构的机器之间保证数据解析的一致性。所以对于从网络抓包获取的、未经处理的原始字节流我们通常假设它是大端序。计算机内存存储因架构而异x86/x64架构是小端序Little-Endian而一些其他处理器可能是大端序。如果你是从本地进程内存中直接读取浮点数例如用C语言指针则需要根据你的系统架构来决定。安全做法对于网络数据优先尝试大端序‘d’。如果解析出来的浮点数完全不对比如变成了一个极小的数或NaN再尝试小端序‘d’。在我们的场景JSON中的数字下其实struct用不到因为JSON解析器已经帮我们把字节流转换成了Python的float对象。我们使用struct是为了将float对象再变回字节以查看其标准内存表示此时字节序的选择只是为了得到一个规范的表示‘d’和‘d’得到的字节序列是相反的但都能通过反向解析得到原值。5.5 技巧使用在线工具快速交叉验证当你对自己的脚本解析结果不确定时强烈推荐使用在线IEEE 754转换器。搜索 “IEEE 754 double precision converter”。在“Decimal”或“Float”输入框里填入你抓到的值如954.5。工具会立即显示其十六进制表示、二进制表示并拆分出S、E、M。 这可以瞬间验证你的Python脚本输出的十六进制结果是否正确。5.6 高级技巧追踪额度变化的“数据指纹”如果你怀疑额度值不仅仅是简单的计算还可能包含版本、时间戳等隐藏信息可以尝试更精细的分析。收集时间序列数据在一天中的不同时间、进行不同操作后多次记录额度浮点数。对比内存表示不要只看十进制值直接对比其完整的64位二进制串。即使十进制值只有微小变化二进制串的变化也可能呈现出某种模式例如只有尾数的低几位在变这可能意味着高位部分编码了其他信息。分析变化位编写脚本计算两次抓取的浮点数的64位表示有多少位不同汉明距离以及不同的位集中在指数区还是尾数区。如果变化总是发生在尾数区的固定几个低位那很可能只是计算精度导致的正常波动。如果变化没有规律或者涉及指数位则可能意味着计算逻辑更复杂或者值被重置/更新了。6. 总结与延伸思考通过这一系列的探索我们完成了一次针对“Claude订阅额度”这个具体场景的浮点数逆向分析实战。我们从最基础的浏览器抓包开始定位到关键数据字段然后利用Python深入探查了浮点数在内存中的奥秘并尝试通过观察其模式来推测后端服务的可能逻辑。这个过程的核心价值不在于“破解”了什么而在于深刻理解了我们日常接触的数据在网络传输和计算机内部是如何被表示和处理的。一个简单的数字954.5背后是IEEE 754标准的严谨定义是8个字节的精密排列是符号、指数、尾数三者的巧妙组合。这种理解对于调试涉及数值计算的复杂Bug、进行跨平台数据交换、甚至进行底层性能优化都是至关重要的基础。个人体会在这一次的探索中我最深的感触是“细节决定深度”。最初只是好奇一个数字怎么显示但顺着这条线往下挖就串联起了网络抓包、数据格式、数值系统、编程技巧等多个知识点。它提醒我在面对任何技术产品时保持这种“好奇心驱动”的探究欲是不断成长的关键。同时它也强化了我的一个工作原则对任何来自外部系统的数据都要保持审慎的信任并通过技术手段进行交叉验证。前端显示的数字未必是后端计算的原始值传输的格式也蕴含着设计者的权衡。最后这个思路可以延伸到很多其他场景。不仅仅是AI服务的额度任何传输数值型指标的系统——比如游戏里的金币余额、物联网设备的传感器读数、金融应用的汇率信息——只要你能够捕获到它的原始数据传输都可以尝试用类似的思路去分析。这就像获得了一把数字世界的“放大镜”让你能看清数据最本真的面貌。当然切记始终要在合法合规、尊重他人服务的框架内使用这项技能。
返回列表