hcaptcha算法分析 dreamland 2025-08-04 2025-08-09 完整流程 [开始hCaptcha验证] –> [接收JWT令牌] –>[分析关键参数] –>[发送请求]
n值数据生成 n值是由浏览器的环境和一些指纹生成的下面我将来分析下这个算法
算法部分 hcaptcha这个部分核心的算法是在wasm里面和vmp里面的 通过解混淆我们知道这个是一个AES的加密算法但它的key和iv分别在wasm里
提取key 我们可以直接引用wasm里生成好的key
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 def _generate_n_key(self): seed = self.key_factors["seed"] key_factor1 = self.key_factors["key_factor1"] key_factor2 = self.key_factors["key_factor2"] key_bytes = list(self.key_factors["key_seed"].to_bytes(4, byteorder="little"))[ :2 ] for step in range(30): if step != 0: seed = (seed * self.LCG_MULTIPLIER) & 0xFFFFFFFFFFFFFFFF if self.key_factors["operator"] == "+": seed = (seed + key_factor1) & 0xFFFFFFFFFFFFFFFF else: seed = (seed - key_factor1) & 0xFFFFFFFFFFFFFFFF base_index = self.key_factors["memory"] + step memory_position = base_index + key_factor2 segment_address = ( ((memory_position // 320) << 3) + memory_position + 1032 - 1075552 ) # get the mask address using modulo 96 and an offset of 8 mask_address = (memory_position % 96) + 8 # read a 32 bit value from memory at the segment address segment_address %= len(self._memory) if segment_address + 4 <= len(self._memory): segment_bytes = self._memory[segment_address : segment_address + 4] else: wrap = segment_address + 4 - len(self._memory) segment_bytes = self._memory[segment_address:] + self._memory[:wrap] segment_value = int.from_bytes(segment_bytes, byteorder="little") mask_address %= len(self._memory) if mask_address + 8 <= len(self._memory): mask_bytes = self._memory[mask_address : mask_address + 8] else: wrap = mask_address + 8 - len(self._memory) mask_bytes = self._memory[mask_address:] + self._memory[:wrap] mask_value = int.from_bytes(mask_bytes, byteorder="little") # calculate a hash value by xoring the segment value with the lower 32 bits of the mask value hash_value = (segment_value ^ (mask_value & 0xFFFFFFFF)) & 0xFF # extract specific bit positions from the state seed # these are at positions 45, 27, and 59 in the 64 bit seed bit45 = (seed >> 45) & 0xFFFFFFFF bit27 = (seed >> 27) & 0xFFFFFFFF bit59 = (seed >> 59) & 0xFFFFFFFF if bit45 & 0x80000000: bit45 = bit45 - 0x100000000 if bit27 & 0x80000000: bit27 = bit27 - 0x100000000 if bit59 & 0x80000000: bit59 = bit59 - 0x100000000 # xor bit45 and bit27 combined = bit45 ^ bit27 shift = bit59 % 32 combined &= 0xFFFFFFFF rotated = ((combined >> shift) | (combined << (32 - shift))) & 0xFFFFFFFF if rotated & 0x80000000: rotated = rotated - 0x100000000 key_byte = (hash_value ^ rotated) & 0xFF key_bytes.append(key_byte) self.key = bytes(key_bytes).hex()
剩下的就简单了直接算法还原