├── .gitignore ├── Cargo.toml ├── device.json ├── sitekeys.json └── src ├── cache.rs ├── device.rs ├── encoder.rs ├── enums.rs ├── extract.rs ├── keys.rs ├── lib.rs ├── main.rs ├── payload.rs ├── reese.rs └── utils.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /tools 3 | /tests 4 | Cargo.lock 5 | .env 6 | /.cargo 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "reese84" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "^1.0.93" 10 | base64 = "0.22.1" 11 | clipboard = "0.5.0" 12 | dotenv = "0.15.0" 13 | enum_index = "0.2.0" 14 | enum_index_derive = "0.2.0" 15 | lazy_static = "1.4.0" 16 | once_cell = "1.20.2" 17 | rand = "0.8.5" 18 | serde = { version = "1.0.200", features = ["serde_derive"]} 19 | serde_json = {version = "1.0.108", features = ["preserve_order"]} 20 | sha1 = "0.10.6" 21 | tokio = {version = "1.37.0", features = ["full"]} 22 | 23 | [dev-dependencies] 24 | rquest = { version = "0.27.7", features = ["gzip", "brotli", "cookies"]} -------------------------------------------------------------------------------- /device.json: -------------------------------------------------------------------------------- 1 | { 2 | "telemetry": { 3 | "mouse_events": [], 4 | "touch_events": [] 5 | }, 6 | "bas_detection": {}, 7 | "sitekey": "", 8 | "static_num": 1, 9 | "property_checks": [ 10 | [ 11 | "vendorSub", 12 | "" 13 | ], 14 | [ 15 | "productSub", 16 | "" 17 | ], 18 | [ 19 | "vendor", 20 | "" 21 | ], 22 | [ 23 | "maxTouchPoints", 24 | "" 25 | ], 26 | [ 27 | "scheduling", 28 | "" 29 | ], 30 | [ 31 | "userActivation", 32 | "" 33 | ], 34 | [ 35 | "doNotTrack", 36 | "" 37 | ], 38 | [ 39 | "geolocation", 40 | "" 41 | ], 42 | [ 43 | "connection", 44 | "" 45 | ], 46 | [ 47 | "plugins", 48 | "" 49 | ], 50 | [ 51 | "mimeTypes", 52 | "" 53 | ], 54 | [ 55 | "pdfViewerEnabled", 56 | "" 57 | ], 58 | [ 59 | "webkitTemporaryStorage", 60 | "" 61 | ], 62 | [ 63 | "webkitPersistentStorage", 64 | "" 65 | ], 66 | [ 67 | "windowControlsOverlay", 68 | "" 69 | ], 70 | [ 71 | "hardwareConcurrency", 72 | "" 73 | ], 74 | [ 75 | "cookieEnabled", 76 | "" 77 | ], 78 | [ 79 | "appCodeName", 80 | "" 81 | ], 82 | [ 83 | "appName", 84 | "" 85 | ], 86 | [ 87 | "appVersion", 88 | "" 89 | ], 90 | [ 91 | "platform", 92 | "" 93 | ], 94 | [ 95 | "product", 96 | "" 97 | ], 98 | [ 99 | "userAgent", 100 | "" 101 | ], 102 | [ 103 | "language", 104 | "" 105 | ], 106 | [ 107 | "languages", 108 | "" 109 | ], 110 | [ 111 | "onLine", 112 | "" 113 | ], 114 | [ 115 | "webdriver", 116 | "" 117 | ], 118 | [ 119 | "getGamepads", 120 | "" 121 | ], 122 | [ 123 | "javaEnabled", 124 | "" 125 | ], 126 | [ 127 | "sendBeacon", 128 | "" 129 | ], 130 | [ 131 | "vibrate", 132 | "" 133 | ], 134 | [ 135 | "deprecatedRunAdAuctionEnforcesKAnonymity", 136 | "" 137 | ], 138 | [ 139 | "protectedAudience", 140 | "" 141 | ], 142 | [ 143 | "bluetooth", 144 | "" 145 | ], 146 | [ 147 | "storageBuckets", 148 | "" 149 | ], 150 | [ 151 | "clipboard", 152 | "" 153 | ], 154 | [ 155 | "credentials", 156 | "" 157 | ], 158 | [ 159 | "keyboard", 160 | "" 161 | ], 162 | [ 163 | "managed", 164 | "" 165 | ], 166 | [ 167 | "mediaDevices", 168 | "" 169 | ], 170 | [ 171 | "storage", 172 | "" 173 | ], 174 | [ 175 | "serviceWorker", 176 | "" 177 | ], 178 | [ 179 | "virtualKeyboard", 180 | "" 181 | ], 182 | [ 183 | "wakeLock", 184 | "" 185 | ], 186 | [ 187 | "deviceMemory", 188 | "" 189 | ], 190 | [ 191 | "userAgentData", 192 | "" 193 | ], 194 | [ 195 | "cookieDeprecationLabel", 196 | "" 197 | ], 198 | [ 199 | "login", 200 | "" 201 | ], 202 | [ 203 | "ink", 204 | "" 205 | ], 206 | [ 207 | "mediaCapabilities", 208 | "" 209 | ], 210 | [ 211 | "hid", 212 | "" 213 | ], 214 | [ 215 | "locks", 216 | "" 217 | ], 218 | [ 219 | "gpu", 220 | "" 221 | ], 222 | [ 223 | "mediaSession", 224 | "" 225 | ], 226 | [ 227 | "permissions", 228 | "" 229 | ], 230 | [ 231 | "presentation", 232 | "" 233 | ], 234 | [ 235 | "usb", 236 | "" 237 | ], 238 | [ 239 | "xr", 240 | "" 241 | ], 242 | [ 243 | "serial", 244 | "" 245 | ], 246 | [ 247 | "adAuctionComponents", 248 | "" 249 | ], 250 | [ 251 | "runAdAuction", 252 | "" 253 | ], 254 | [ 255 | "canLoadAdAuctionFencedFrame", 256 | "" 257 | ], 258 | [ 259 | "canShare", 260 | "" 261 | ], 262 | [ 263 | "share", 264 | "" 265 | ], 266 | [ 267 | "clearAppBadge", 268 | "" 269 | ], 270 | [ 271 | "getBattery", 272 | "" 273 | ], 274 | [ 275 | "getUserMedia", 276 | "" 277 | ], 278 | [ 279 | "requestMIDIAccess", 280 | "" 281 | ], 282 | [ 283 | "requestMediaKeySystemAccess", 284 | "" 285 | ], 286 | [ 287 | "setAppBadge", 288 | "" 289 | ], 290 | [ 291 | "webkitGetUserMedia", 292 | "" 293 | ], 294 | [ 295 | "clearOriginJoinedAdInterestGroups", 296 | "" 297 | ], 298 | [ 299 | "createAuctionNonce", 300 | "" 301 | ], 302 | [ 303 | "joinAdInterestGroup", 304 | "" 305 | ], 306 | [ 307 | "leaveAdInterestGroup", 308 | "" 309 | ], 310 | [ 311 | "updateAdInterestGroups", 312 | "" 313 | ], 314 | [ 315 | "deprecatedReplaceInURN", 316 | "" 317 | ], 318 | [ 319 | "deprecatedURNToURL", 320 | "" 321 | ], 322 | [ 323 | "getInstalledRelatedApps", 324 | "" 325 | ], 326 | [ 327 | "getInterestGroupAdAuctionData", 328 | "" 329 | ], 330 | [ 331 | "registerProtocolHandler", 332 | "" 333 | ], 334 | [ 335 | "unregisterProtocolHandler", 336 | "" 337 | ] 338 | ], 339 | "language": "de-DE", 340 | "languages": { 341 | "disabled": false, 342 | "list": [ 343 | "de-DE" 344 | ] 345 | }, 346 | "timings": { 347 | "current_time": null, 348 | "last_modification_time": null, 349 | "performance_now": null, 350 | "document_timeline_current_time": null, 351 | "performane_navigation_start": null 352 | }, 353 | "mime_types": [ 354 | [ 355 | "0", 356 | { 357 | "suffix": "pdf", 358 | "content_type": "application/pdf", 359 | "plugin_name": "internal-pdf-viewer" 360 | } 361 | ], 362 | [ 363 | "1", 364 | { 365 | "suffix": "pdf", 366 | "content_type": "text/pdf", 367 | "plugin_name": "internal-pdf-viewer" 368 | } 369 | ], 370 | [ 371 | "application/pdf", 372 | { 373 | "suffix": "pdf", 374 | "content_type": "application/pdf", 375 | "plugin_name": "internal-pdf-viewer" 376 | } 377 | ], 378 | [ 379 | "text/pdf", 380 | { 381 | "suffix": "pdf", 382 | "content_type": "text/pdf", 383 | "plugin_name": "internal-pdf-viewer" 384 | } 385 | ] 386 | ], 387 | "screen": { 388 | "width": 1920, 389 | "height": 1080, 390 | "availHeight": 1032, 391 | "availLeft": 0, 392 | "availTop": 0, 393 | "availWidth": 1920, 394 | "pixelDepth": 24, 395 | "innerWidth": 1920, 396 | "innerHeight": 911, 397 | "outerWidth": 1920, 398 | "outerHeight": 1032, 399 | "pixelRatio": 1, 400 | "orientation_type": "landscape-primary", 401 | "screenX": 0, 402 | "screenY": 0 403 | }, 404 | "timezone_offset": 1, 405 | "indexed_db": true, 406 | "add_behavior": false, 407 | "bitwise_function": null, 408 | "open_database": false, 409 | "cpu_class": "unknown", 410 | "platform": "Win32", 411 | "do_not_track": "unknown", 412 | "plugins_list": "Chrome PDF Viewer::Portable Document Format::application/pdf~pdf,text/pdf~pdf;Chromium PDF Viewer::Portable Document Format::application/pdf~pdf,text/pdf~pdf;Microsoft Edge PDF Viewer::Portable Document Format::application/pdf~pdf,text/pdf~pdf;PDF Viewer::Portable Document Format::application/pdf~pdf,text/pdf~pdf;WebKit built-in PDF::Portable Document Format::application/pdf~pdf,text/pdf~pdf", 413 | "plugin_functions_names": { 414 | "namedItem": "namedItem", 415 | "item": "item", 416 | "refresh": "refresh" 417 | }, 418 | "canvas": { 419 | "point_in_path": true, 420 | "webp_format": true, 421 | "globalCompositeOperation_is_screen": true, 422 | "hash": "6bcd7d8cf9dd30bb0b4378d8f4977c0b49bccdc8" 423 | }, 424 | "image": { 425 | "dataURL": "AAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAA9JREFUGFdjZEADjKQLAAAA7gAFLaYDxAAAAABJRU5ErkJggg==" 426 | }, 427 | "web_gl": { 428 | "hash": "2e6ef05efde758669794f94cc6409b5c9b253e46", 429 | "supportedExtensions": "EXT_clip_control;EXT_color_buffer_float;EXT_color_buffer_half_float;EXT_conservative_depth;EXT_depth_clamp;EXT_float_blend;EXT_polygon_offset_clamp;EXT_texture_compression_bptc;EXT_texture_compression_rgtc;EXT_texture_filter_anisotropic;EXT_texture_mirror_clamp_to_edge;EXT_texture_norm16;NV_shader_noperspective_interpolation;OES_draw_buffers_indexed;OES_sample_variables;OES_shader_multisample_interpolation;OES_texture_float_linear;OVR_multiview2;WEBGL_clip_cull_distance;WEBGL_compressed_texture_astc;WEBGL_compressed_texture_etc;WEBGL_compressed_texture_etc1;WEBGL_compressed_texture_s3tc;WEBGL_compressed_texture_s3tc_srgb;WEBGL_debug_renderer_info;WEBGL_debug_shaders;WEBGL_lose_context;WEBGL_multi_draw;WEBGL_polygon_mode;WEBGL_stencil_texturing", 430 | "line_width_range": [ 431 | 1, 432 | 1 433 | ], 434 | "point_size_range": [ 435 | 1, 436 | 1023 437 | ], 438 | "alpha_bits": 8, 439 | "antialias": true, 440 | "blue_bits": 8, 441 | "depth_bits": 24, 442 | "green_bits": 8, 443 | "max_anisotropy": 16, 444 | "max_combined_texture_image_units": 64, 445 | "max_cube_map_texture_size": 16384, 446 | "max_fragment_uniform_vectors": 4096, 447 | "max_renderbuffer_size": 8192, 448 | "max_texture_image_units": 32, 449 | "max_texture_size": 8192, 450 | "max_varying_vectors": 31, 451 | "max_vertex_attribs": 16, 452 | "max_vertex_texture_image_units": 32, 453 | "max_vertex_uniform_vectors": 4096, 454 | "max_viewport_dims": [ 455 | 8192, 456 | 8192 457 | ], 458 | "red_bits": 8, 459 | "renderer": "WebKit WebGL", 460 | "shading_language_version": "WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)", 461 | "stencil_bits": 0, 462 | "vendor": "WebKit", 463 | "version": "WebGL 2.0 (OpenGL ES 3.0 Chromium)", 464 | "vertex_high_float_precision": 23, 465 | "vertex_high_float_rangeMin": 127, 466 | "vertex_high_float_rangeMax": 127, 467 | "vertex_medium_float_precision": 10, 468 | "vertex_medium_float_rangeMin": 15, 469 | "vertex_medium_float_rangeMax": 15, 470 | "vertex_low_float_precision": 10, 471 | "vertex_low_float_rangeMin": 15, 472 | "vertex_low_float_rangeMax": 15, 473 | "fragment_high_float_precision": 23, 474 | "fragment_high_float_rangeMin": 127, 475 | "fragment_high_float_rangeMax": 127, 476 | "fragment_medium_float_precision": 10, 477 | "fragment_medium_float_rangeMin": 15, 478 | "fragment_medium_float_rangeMax": 15, 479 | "fragment_low_float_precision": 10, 480 | "fragment_low_float_rangeMin": 15, 481 | "fragment_low_float_rangeMax": 15, 482 | "vertex_high_int_precision": 0, 483 | "vertex_high_int_rangeMin": 31, 484 | "vertex_high_int_rangeMax": 30, 485 | "vertex_medium_int_precision": 0, 486 | "vertex_medium_int_rangeMin": 15, 487 | "vertex_medium_int_rangeMax": 14, 488 | "vertex_low_int_precision": 0, 489 | "vertex_low_int_rangeMin": 15, 490 | "vertex_low_int_rangeMax": 14, 491 | "fragment_high_int_precision": 0, 492 | "fragment_high_int_rangeMin": 31, 493 | "fragment_high_int_rangeMax": 30, 494 | "fragment_medium_int_precision": 0, 495 | "fragment_medium_int_rangeMin": 15, 496 | "fragment_medium_int_rangeMax": 14, 497 | "fragment_low_int_precision": 0, 498 | "fragment_low_int_rangeMin": 15, 499 | "fragment_low_int_rangeMax": 14, 500 | "unmasked_vendor": "Google Inc. (Google)", 501 | "unmasked_renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)" 502 | }, 503 | "small_image": { 504 | "dataURL": "AAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAAXNSR0IArs4c6QAAAA9JREFUGFdjZEADjKQLAAAA7gAFLaYDxAAAAABJRU5ErkJggg==" 505 | }, 506 | "web_gl_prototypes": { 507 | "getParameter_name": "getParameter", 508 | "getParameter_exists": true 509 | }, 510 | "touch_data": { 511 | "maxTouchPoints": 0, 512 | "can_create_touchEvent": false, 513 | "ontouchstart_unequal_undefined": false 514 | }, 515 | "video_checks": { 516 | "can_play_ogg": "nope", 517 | "can_play_mp4": "probably", 518 | "can_play_webm": "probably" 519 | }, 520 | "audio_checks": { 521 | "can_play_ogg": "probably", 522 | "can_play_mpeg": "probably", 523 | "can_play_wav": "probably", 524 | "can_play_xm4a": "maybe", 525 | "can_play_empty": "nope", 526 | "can_play_mp4": "probably" 527 | }, 528 | "vendor": "Google Inc.", 529 | "product": "Gecko", 530 | "productSub": "20030107", 531 | "chrome_properties": { 532 | "is_internet_explorer": false, 533 | "chrome_app_checks": { 534 | "loadTimes_is_native": true, 535 | "chrome_app_functions": [ 536 | [ 537 | "isInstalled", 538 | "vwec" 539 | ], 540 | [ 541 | "getDetails", 542 | "vwec" 543 | ], 544 | [ 545 | "getIsInstalled", 546 | "vwec" 547 | ], 548 | [ 549 | "installState", 550 | "vwec" 551 | ], 552 | [ 553 | "runningState", 554 | "vwec" 555 | ], 556 | [ 557 | "InstallState", 558 | "vwec" 559 | ], 560 | [ 561 | "RunningState", 562 | "vwec" 563 | ] 564 | ], 565 | "chrome_app_properties": [ 566 | [ 567 | "loadTimes.length", 568 | 0 569 | ], 570 | [ 571 | "loadTimes.name", 572 | 1 573 | ], 574 | [ 575 | "loadTimes.prototype", 576 | 1 577 | ], 578 | [ 579 | "csi.length", 580 | 0 581 | ], 582 | [ 583 | "csi.name", 584 | 1 585 | ], 586 | [ 587 | "csi.prototype", 588 | 1 589 | ], 590 | [ 591 | "app.isInstalled", 592 | 0 593 | ], 594 | [ 595 | "app.getDetails", 596 | 2 597 | ], 598 | [ 599 | "app.getIsInstalled", 600 | 2 601 | ], 602 | [ 603 | "app.installState", 604 | 2 605 | ], 606 | [ 607 | "app.runningState", 608 | 2 609 | ], 610 | [ 611 | "app.InstallState", 612 | 3 613 | ], 614 | [ 615 | "app.RunningState", 616 | 3 617 | ] 618 | ] 619 | }, 620 | "webdriver": false, 621 | "is_chrome": true, 622 | "connection_rtt": 0, 623 | "duckduckgo": null 624 | }, 625 | "random_properties": { 626 | "history_length": 2, 627 | "hardware_concurrency": 16, 628 | "top_unequal_self": false, 629 | "getBattery_exists": true, 630 | "console_debug_name": "debug", 631 | "debug_exists": true, 632 | "phantom": false, 633 | "callPhantom": false, 634 | "empty_array": [], 635 | "window_presistent": 1, 636 | "window_temporary": 0, 637 | "performanceObserver": { 638 | "supportedEntryTypes": [ 639 | "element", 640 | "event", 641 | "first-input", 642 | "largest-contentful-paint", 643 | "layout-shift", 644 | "long-animation-frame", 645 | "longtask", 646 | "mark", 647 | "measure", 648 | "navigation", 649 | "paint", 650 | "resource", 651 | "visibility-state" 652 | ] 653 | }, 654 | "sentryInWindow": false 655 | }, 656 | "protocol": { 657 | "location_protocol": "https:" 658 | }, 659 | "fonts": [ 660 | "Calibri", 661 | "Century", 662 | "Haettenschweiler", 663 | "Leelawadee", 664 | "Marlett", 665 | "Pristina" 666 | ], 667 | "scripts": { 668 | "count": 1, 669 | "non_script_count": 3, 670 | "in_documentElement": [], 671 | "in_head": [ 672 | { 673 | "src": "https://www.immobilienscout24.de/assets/immo-1-17" 674 | } 675 | ], 676 | "in_body": [] 677 | }, 678 | "executed_functions": { 679 | "func_1": "ires that 'this' be a Function", 680 | "func_2": "ires that 'this' be a Function", 681 | "func_3": false, 682 | "func_4": ":@\b\u0017?ZnH_c\u0005\"\u0005]^I|l\u000e$>" 683 | }, 684 | "window_property_descriptors": "WritableStreamDefaultController;;;WindowControlsOverlayGeometryChangeEvent;;;VirtualKeyboardGeometryChangeEvent;;;TransformStreamDefaultController;;;SVGComponentTransferFunctionElement;;;SVGAnimatedPreserveAspectRatio;;;ReadableStreamDefaultController;;;RTCPeerConnectionIceErrorEvent;;;OffscreenCanvasRenderingContext2D;;;NavigationCurrentEntryChangeEvent;;;MediaStreamAudioDestinationNode;;;ContentVisibilityAutoStateChangeEvent;;;BrowserCaptureMediaStreamTrack;;;oncontentvisibilityautostatechange;;;WebTransportBidirectionalStream;;;WebTransportDatagramDuplexStream;;;AuthenticatorAssertionResponse;;;AuthenticatorAttestationResponse;;;BluetoothCharacteristicProperties;;;BluetoothRemoteGATTCharacteristic;;;PresentationConnectionAvailableEvent;;;PresentationConnectionCloseEvent;;;USBIsochronousInTransferPacket;;;USBIsochronousInTransferResult;;;USBIsochronousOutTransferPacket;;;USBIsochronousOutTransferResult;;;PerformanceLongAnimationFrameTiming;;;webkitResolveLocalFileSystemURL;;;reese84InternalProtectionLoaded", 685 | "window_30_property_names": [ 686 | "correct_ua", 687 | "x_url_c", 688 | "GoogleAnalyt$", 689 | "ga", 690 | "usaFunc", 691 | "usaId", 692 | "lightningjs", 693 | "usabilla_liv$", 694 | "customUsabil$", 695 | "_fs_ready", 696 | "pushValuesTo$", 697 | "pushValuesTo$", 698 | "usblCallBack", 699 | "otStubData", 700 | "postscribe", 701 | "google_tag_m$", 702 | "winbackDelta", 703 | "getTxType", 704 | "getConfig", 705 | "LogUtils", 706 | "recaptcha", 707 | "closure_lm_9$", 708 | "gaGlobal", 709 | "gaplugins", 710 | "gaData", 711 | "Optanon", 712 | "OneTrust", 713 | "OnetrustActi$", 714 | "OptanonActiv$", 715 | "divolte" 716 | ], 717 | "visual_viewport": { 718 | "width": 1920, 719 | "height": 911, 720 | "scale": 1 721 | }, 722 | "html_create_function_names": [ 723 | [ 724 | 0, 725 | "createAttribute" 726 | ], 727 | [ 728 | 1, 729 | "createElement" 730 | ], 731 | [ 732 | 2, 733 | "createElementNS" 734 | ], 735 | [ 736 | 3, 737 | null 738 | ], 739 | [ 740 | 4, 741 | null 742 | ], 743 | [ 744 | 5, 745 | null 746 | ] 747 | ], 748 | "high_surrogate": [], 749 | "skip_reese_expiration": false, 750 | "created_divs": { 751 | "block_1": [ 752 | [ 753 | "SET_KEY", 754 | "n", 755 | "n", 756 | true 757 | ], 758 | [ 759 | "SET_KEY", 760 | "s", 761 | "s", 762 | true 763 | ], 764 | [ 765 | "SET_KEY", 766 | "s", 767 | "s", 768 | true 769 | ], 770 | [ 771 | "SET_KEY", 772 | "n", 773 | "n", 774 | true 775 | ], 776 | [ 777 | "SET_KEY", 778 | "s", 779 | "s", 780 | true 781 | ], 782 | [ 783 | "SET_KEY", 784 | "o", 785 | "u", 786 | false 787 | ] 788 | ], 789 | "block_2": [ 790 | [ 791 | "SET_KEY", 792 | "n", 793 | "n", 794 | true 795 | ], 796 | [ 797 | "SET_KEY", 798 | "s", 799 | "s", 800 | true 801 | ], 802 | [ 803 | "SET_KEY", 804 | "s", 805 | "s", 806 | true 807 | ], 808 | [ 809 | "SET_KEY", 810 | "n", 811 | "n", 812 | true 813 | ], 814 | [ 815 | "SET_KEY", 816 | "s", 817 | "s", 818 | true 819 | ], 820 | [ 821 | "SET_KEY", 822 | "o", 823 | "u", 824 | false 825 | ] 826 | ] 827 | }, 828 | "typeof_checks": [ 829 | { 830 | "type_of": "function", 831 | "stringified": "function toString() { [native code] }", 832 | "stringified_no_name": "function () { [native code] }", 833 | "stringified_no_func": " () { [native code] }", 834 | "func_name": "toString" 835 | }, 836 | { 837 | "type_of": "function", 838 | "stringified": "function stringify() { [native code] }", 839 | "stringified_no_name": "function () { [native code] }", 840 | "stringified_no_func": " () { [native code] }", 841 | "func_name": "stringify" 842 | }, 843 | { 844 | "type_of": "function", 845 | "stringified": "function OwnPropertyDescriptor() { [native code] }", 846 | "stringified_no_name": "function () { [native code] }", 847 | "stringified_no_func": " () { [native code] }", 848 | "func_name": "OwnPropertyDescriptor" 849 | }, 850 | { 851 | "type_of": "function", 852 | "stringified": "function call() { [native code] }", 853 | "stringified_no_name": "function () { [native code] }", 854 | "stringified_no_func": " () { [native code] }", 855 | "func_name": "call" 856 | }, 857 | { 858 | "type_of": "function", 859 | "stringified": "function apply() { [native code] }", 860 | "stringified_no_name": "function () { [native code] }", 861 | "stringified_no_func": " () { [native code] }", 862 | "func_name": "apply" 863 | }, 864 | { 865 | "type_of": "function", 866 | "stringified": "function bind() { [native code] }", 867 | "stringified_no_name": "function () { [native code] }", 868 | "stringified_no_func": " () { [native code] }", 869 | "func_name": "bind" 870 | }, 871 | { 872 | "type_of": "function", 873 | "stringified": "function getParameter() { [native code] }", 874 | "stringified_no_name": "function () { [native code] }", 875 | "stringified_no_func": " () { [native code] }", 876 | "func_name": "getParameter" 877 | }, 878 | { 879 | "type_of": "function", 880 | "stringified": "function getBattery() { [native code] }", 881 | "stringified_no_name": "function () { [native code] }", 882 | "stringified_no_func": " () { [native code] }", 883 | "func_name": "getBattery" 884 | }, 885 | { 886 | "type_of": "function", 887 | "stringified": "function debug() { [native code] }", 888 | "stringified_no_name": "function () { [native code] }", 889 | "stringified_no_func": " () { [native code] }", 890 | "func_name": "debug" 891 | }, 892 | { 893 | "type_of": "function", 894 | "stringified": "function () { [native code] }", 895 | "stringified_no_name": "function () { [native code] }", 896 | "stringified_no_func": " () { [native code] }", 897 | "func_name": "" 898 | }, 899 | { 900 | "type_of": "function", 901 | "stringified": "function () { [native code] }", 902 | "stringified_no_name": "function () { [native code] }", 903 | "stringified_no_func": " () { [native code] }", 904 | "func_name": "get window" 905 | } 906 | ], 907 | "navigator_property_checks": [ 908 | [ 909 | "SL/NgizWILql4kYpHzyFS8v6FynjaEPBVdlfWIQ2RxA=", 910 | "SET_KEY" 911 | ], 912 | [ 913 | "SL/NgizWILql4kYpHzyFS8v6Fyn4aFTBQdlKWKo2YhC0it0dFDY=", 914 | "SET_KEY" 915 | ], 916 | [ 917 | "SL/NgizWILql4kYpHzyFS8v6Fyn5aF3BS9lCWIM2UxCSivsdMjY=", 918 | "SET_KEY" 919 | ], 920 | [ 921 | "Ub/QgiXWJ7qp4nQpLTy3S9j6LynfaHPBZdlsWA==", 922 | "SET_KEY" 923 | ], 924 | [ 925 | "Ur/Zgj3WLLq84lcpFDyGS+X6Byn1aEDBVNlDWA==", 926 | "SET_KEY" 927 | ], 928 | [ 929 | "SL/NgizWILql4kYpHzyFS8v6Fyn9aFnBU9lZWJo2ShCeivcdDjZ03nx9cSZKv42ChdaXuq7iKSnHPA==", 930 | "SET_KEY" 931 | ], 932 | [ 933 | "Ub/QgiXWJ7qp4nQpPjyuS+b6NSnWaGHBeNl7WKo2bxCsitId", 934 | "SET_KEY" 935 | ], 936 | [ 937 | "SL/NgizWILql4kYpHzyFS8v6FynxaFHBX9lYWI82WxCwitkdDjZ03mB9dyY=", 938 | "SET_KEY" 939 | ], 940 | [ 941 | "SL/NgizWILql4kYpHzyFS8v6FynlaEXBT9lMWJE2UxCGiuMdNjZN3lh9", 942 | "SET_KEY" 943 | ] 944 | ], 945 | "shifted_value": 0, 946 | "version_state": "beta", 947 | "version_num": 28 948 | } -------------------------------------------------------------------------------- /sitekeys.json: -------------------------------------------------------------------------------- 1 | { 2 | "tKJ+r2WSPkB/i/TfO8lLsFzGPjXWlBTOr0GMlG8jsT8=": { 3 | "site": "Smythstoys", 4 | "blacklist": false 5 | }, 6 | "WTrwdhd6Mf+OcJ0kbmLRQGXDD1Pk9NInh0xCME4KY": { 7 | "site": "Pokemoncenter", 8 | "blacklist": false 9 | } 10 | } -------------------------------------------------------------------------------- /src/cache.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, sync::Arc, time::Duration}; 2 | use tokio::{sync::Mutex, time::interval}; 3 | 4 | use once_cell::sync::Lazy; 5 | 6 | use crate::{encoder::Encoder, extract::Extractor, utils::get_unix_ts}; 7 | 8 | #[derive(Clone)] 9 | pub struct CacheEntry { 10 | pub encoders: Vec, 11 | pub extractor: Extractor, 12 | last_used: u128 13 | } 14 | 15 | #[derive(Default)] 16 | pub struct Cache { 17 | inner: Mutex> 18 | } 19 | 20 | impl Cache { 21 | pub async fn insert(&self, sig: u64, encoders: Vec, extractor: Extractor) { 22 | self.inner.lock() 23 | .await 24 | .insert(sig, CacheEntry { 25 | encoders, 26 | extractor, 27 | last_used: get_unix_ts() 28 | }); 29 | } 30 | pub async fn get(&self, sig: u64) -> Option { 31 | match self.inner.lock().await.get_mut(&sig) { 32 | Some(e) => { 33 | e.last_used = get_unix_ts(); 34 | Some(e.clone()) 35 | }, 36 | None => None 37 | } 38 | } 39 | 40 | // Check cache every 60 seconds, remove entries 41 | // which havent been used for > 10 mins 42 | const GC_INTERVAL: u64 = 60; 43 | const GC_TIMEOUT: u128 = 1000 * 60 * 10; 44 | 45 | pub async fn gc(&self) { 46 | let mut interval = interval(Duration::from_secs(Cache::GC_INTERVAL)); 47 | interval.tick().await; 48 | 49 | loop { 50 | interval.tick().await; 51 | 52 | let now = get_unix_ts(); 53 | let mut cache = self.inner.lock().await; 54 | 55 | let removable_sigs = cache.iter() 56 | .filter(|(_, v)| (now - v.last_used) > Cache::GC_TIMEOUT) 57 | .map(|p| *p.0) 58 | .collect::>(); 59 | 60 | for sig in removable_sigs { 61 | cache.remove(&sig); 62 | } 63 | } 64 | } 65 | } 66 | 67 | pub static CACHE: Lazy> = Lazy::new(|| { 68 | let cache = Arc::new(Cache::default()); 69 | { 70 | let cache = Arc::clone(&cache); 71 | tokio::spawn(async move {cache.gc().await}); 72 | } 73 | 74 | cache 75 | }); 76 | 77 | #[cfg(test)] 78 | mod tests { 79 | use std::time::Duration; 80 | use super::CACHE; 81 | 82 | #[tokio::test] 83 | async fn cache() { 84 | 85 | CACHE.get(100).await; 86 | tokio::time::sleep(Duration::from_secs(100)).await 87 | } 88 | } -------------------------------------------------------------------------------- /src/device.rs: -------------------------------------------------------------------------------- 1 | use serde_json::Value; 2 | use once_cell::sync::Lazy; 3 | 4 | pub static DEVICE: Lazy = Lazy::new(|| { 5 | let json_str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/device.json")); 6 | let device: Value = serde_json::from_str(&json_str).unwrap(); 7 | device 8 | }); -------------------------------------------------------------------------------- /src/encoder.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use anyhow::Result; 4 | use base64::{Engine as _, engine::general_purpose}; 5 | use serde_json; 6 | 7 | use crate::{enums::EncoderIndices, keys::{DEFAULT_ENCODER_INDICES, WAF_ENCODER_INDICES}}; 8 | 9 | pub trait Encodable { 10 | fn prepare(&self) -> String; 11 | } 12 | 13 | impl Encodable for &str { 14 | fn prepare(&self) -> String { 15 | format!("\"{}\"", self) 16 | } 17 | } 18 | 19 | impl Encodable for String { 20 | fn prepare(&self) -> String { 21 | format!("\"{}\"", self) 22 | } 23 | } 24 | 25 | impl Encodable for i32 { 26 | fn prepare(&self) -> String { 27 | self.to_string() 28 | } 29 | } 30 | 31 | impl Encodable for u32 { 32 | fn prepare(&self) -> String { 33 | self.to_string() 34 | } 35 | } 36 | 37 | impl Encodable for u128 { 38 | fn prepare(&self) -> String { 39 | self.to_string() 40 | } 41 | } 42 | 43 | impl Encodable for usize { 44 | fn prepare(&self) -> String { 45 | self.to_string() 46 | } 47 | } 48 | 49 | impl Encodable for serde_json::Value { 50 | fn prepare(&self) -> String { 51 | let stringified = serde_json::to_string(&self).unwrap(); 52 | escape_unicode(stringified) 53 | } 54 | } 55 | 56 | fn escape_unicode(unescaped: String) -> String { 57 | let mut escaped = String::new(); 58 | for c in unescaped.chars() { 59 | if c as u8 >= 127 { 60 | escaped.push_str(&format!("\\u{:04x}", c as u8)); 61 | } else { 62 | escaped.push(c as char); 63 | } 64 | } 65 | escaped 66 | } 67 | 68 | #[derive(Clone)] 69 | struct Xorshift { 70 | encoder_seed: u64, 71 | session_seed: u64, 72 | iterations: u8 73 | } 74 | 75 | impl Xorshift { 76 | pub fn new(l0: u64, hi: u64, iterations: u8) -> Self { 77 | Xorshift { encoder_seed: l0, session_seed: hi, iterations: iterations } 78 | } 79 | 80 | fn generate(&mut self) -> u8 { 81 | let mut aa: i32 = self.encoder_seed as i32; 82 | let za = self.session_seed; 83 | self.encoder_seed = za; 84 | aa ^= aa << 23; 85 | aa ^= aa >> 17; 86 | aa ^= za as i32; 87 | aa ^= za as i32 >> 26; 88 | self.session_seed = aa as u64; 89 | ((self.encoder_seed + self.session_seed) & 255) as u8 90 | } 91 | 92 | pub fn fill(&mut self) -> Vec { 93 | let mut encoder_arr: Vec = Vec::new(); 94 | for _ in 0..self.iterations { 95 | encoder_arr.push(self.generate()); 96 | } 97 | return encoder_arr; 98 | } 99 | } 100 | //#[derive(Debug)] 101 | #[derive(PartialEq, Clone)] 102 | pub enum Modifiers { 103 | Switch = 0, 104 | LRShift = 1, 105 | IncludeEncArr = 2, 106 | TripleXor = 3, 107 | Rotate = 4, 108 | Reverse = 5, 109 | XorAdd = 6 110 | } 111 | 112 | #[derive(Clone)] 113 | pub struct Encoder { 114 | pub _id: u64, 115 | pub session_seed: u64, 116 | encoder_iterations: u8, 117 | encode_arr: Vec, 118 | data: Vec, 119 | steps: Vec, 120 | include_encode_arr_start: usize, 121 | include_encode_arr_end: usize, 122 | rotation_index: usize, // navigates through indices 123 | rotation_indices: Vec, 124 | l_r_shift_index: usize, 125 | triple_xor_init_values: Vec, 126 | triple_xor_start_indeces: Vec, 127 | triple_xor_end_indeces: Vec, 128 | xor_add_start_indeces: Vec, 129 | xor_add_end_indeces: Vec, 130 | l_r_shift_indeces: Vec, 131 | triple_xor_index: usize, 132 | xor_add_index: usize, 133 | } 134 | 135 | impl std::ops::Index for Vec { 136 | type Output = Encoder; 137 | 138 | fn index(&self, index: EncoderIndices) -> &Self::Output { 139 | &self[index as usize] 140 | } 141 | } 142 | 143 | impl std::ops::IndexMut for Vec { 144 | fn index_mut(&mut self, index: EncoderIndices) -> &mut Self::Output { 145 | &mut self[index as usize] 146 | } 147 | } 148 | 149 | impl Encoder { 150 | 151 | pub fn new(encoder_seed: u64, session_seed: u64, encoder_iterations: u8) -> Self { 152 | Encoder { 153 | _id: encoder_seed, 154 | session_seed: session_seed, 155 | encoder_iterations, 156 | encode_arr: Xorshift::new(encoder_seed, session_seed, encoder_iterations).fill(), 157 | data: vec![], 158 | steps: vec![], 159 | include_encode_arr_start: 0, 160 | include_encode_arr_end: 0, 161 | rotation_index: 0, 162 | l_r_shift_index: 0, 163 | triple_xor_init_values: Vec::new(), 164 | triple_xor_start_indeces: Vec::new(), 165 | triple_xor_end_indeces: Vec::new(), 166 | xor_add_start_indeces: Vec::new(), 167 | xor_add_end_indeces: Vec::new(), 168 | rotation_indices: Vec::new(), 169 | l_r_shift_indeces: Vec::new(), 170 | triple_xor_index: 0, 171 | xor_add_index: 0, 172 | } 173 | } 174 | 175 | pub fn update_session_seed(&mut self, session_seed: u64) { 176 | self.session_seed = session_seed; 177 | self.encode_arr = Xorshift::new(self._id, session_seed, self.encoder_iterations).fill() 178 | } 179 | 180 | fn reset(&mut self) { 181 | self.triple_xor_index = 0; 182 | self.xor_add_index = 0; 183 | self.rotation_index = 0; 184 | self.l_r_shift_index = 0; 185 | } 186 | 187 | pub fn set_include_encode_arr_values(&mut self, start: usize, end: usize) { 188 | self.include_encode_arr_start = start; 189 | self.include_encode_arr_end = end; 190 | } 191 | 192 | pub fn add_rotate_index(&mut self, index: usize) { 193 | self.rotation_indices.push(index) 194 | } 195 | 196 | pub fn add_l_r_shift_index(&mut self, index: usize) { 197 | self.l_r_shift_indeces.push(index) 198 | } 199 | 200 | pub fn add_triple_xor_values(&mut self, val: u8, start: usize, end: usize) { 201 | self.triple_xor_init_values.push(val); 202 | self.triple_xor_start_indeces.push(start); 203 | self.triple_xor_end_indeces.push(end); 204 | } 205 | 206 | pub fn add_xor_add_values(&mut self, start: usize, end: usize) { 207 | self.xor_add_start_indeces.push(start); 208 | self.xor_add_end_indeces.push(end); 209 | } 210 | 211 | fn switch_pairs(&mut self) { 212 | let max_index = self.data.len() / 2; 213 | //for i in 0..max_index { 214 | // let temp = self.data[i * 2]; 215 | // self.data[i * 2] = self.data[i * 2 + 1]; 216 | // self.data[i * 2 + 1] = temp; 217 | //} 218 | for i in 0..max_index { 219 | self.data.swap(i * 2, i * 2 + 1) 220 | } 221 | } 222 | 223 | fn left_right_shift_or(&mut self) { 224 | let max_index = self.data.len(); 225 | let shift_count = self.encode_arr[self.l_r_shift_indeces[self.l_r_shift_index]] % 7 + 1; 226 | for i in 0..max_index { 227 | self.data[i] = self.data[i] << shift_count | self.data[i] >> 8 - shift_count 228 | } 229 | self.l_r_shift_index += 1; 230 | } 231 | 232 | fn include_encode_arr(&mut self) { 233 | let max_index = self.data.len(); 234 | let include_encode_arr_part = &self.encode_arr[self.include_encode_arr_start..self.include_encode_arr_end]; 235 | let modulus = include_encode_arr_part.len(); 236 | let mut output: Vec = Vec::new(); 237 | for i in 0..max_index { 238 | output.push(self.data[i]); 239 | output.push(include_encode_arr_part[i % modulus]); 240 | } 241 | self.data = output; 242 | } 243 | 244 | fn triple_xor(&mut self) { 245 | 246 | let mut triple_xor_init_val = self.triple_xor_init_values[self.triple_xor_index]; 247 | 248 | let max_index = self.data.len(); 249 | let triple_xor_range = self.triple_xor_start_indeces[self.triple_xor_index]..self.triple_xor_end_indeces[self.triple_xor_index]; 250 | let triple_xor_part = &self.encode_arr[triple_xor_range]; 251 | let modulus = triple_xor_part.len(); 252 | let mut output: Vec = Vec::new(); 253 | for i in 0..max_index { 254 | let result = self.data[i] ^ triple_xor_part[i % modulus] ^ triple_xor_init_val; 255 | output.push(result); 256 | triple_xor_init_val = result; 257 | } 258 | self.data = output; 259 | self.triple_xor_index += 1 260 | } 261 | 262 | fn rotate(&mut self) { 263 | let max_index = self.data.len(); 264 | let mut output: Vec = Vec::new(); 265 | for i in 0..max_index { 266 | output.push(self.data[((i + self.encode_arr[self.rotation_indices[self.rotation_index]] as usize) % max_index) as usize]); 267 | } 268 | self.data = output; 269 | self.rotation_index += 1; 270 | } 271 | 272 | fn reverse(&mut self) { 273 | self.data.reverse(); 274 | } 275 | 276 | fn xor_add(&mut self) { 277 | let max_index = self.data.len(); 278 | let xor_add_range = self.xor_add_start_indeces[self.xor_add_index]..self.xor_add_end_indeces[self.xor_add_index]; 279 | let xor_add_part = &self.encode_arr[xor_add_range]; 280 | let modulus = xor_add_part.len(); 281 | let mut output: Vec = Vec::new(); 282 | for i in 0..max_index { 283 | let val1 = xor_add_part[i % modulus] as u16 & 127; 284 | let result = (self.data[i] as u16 + val1) % 256 ^ 128; 285 | output.push(result as u8); 286 | } 287 | self.data = output; 288 | self.xor_add_index += 1; 289 | } 290 | 291 | pub fn add_step(&mut self, id: Modifiers) { 292 | self.steps.push(id); 293 | } 294 | 295 | pub fn encode(&mut self, data: impl Encodable) -> String { 296 | 297 | self.reset(); 298 | 299 | let temp = data.prepare(); 300 | //println!("{}", temp); 301 | self.data = temp.as_bytes().to_vec(); 302 | //println!("{:?}", self.steps); 303 | //println!("{:?}", self.data); 304 | 305 | let mut steps = self.steps.clone().into_iter(); 306 | loop { 307 | match steps.next() { 308 | Some(s) => match s { 309 | Modifiers::Switch => self.switch_pairs(), 310 | Modifiers::LRShift => self.left_right_shift_or(), 311 | Modifiers::IncludeEncArr => self.include_encode_arr(), 312 | Modifiers::TripleXor => self.triple_xor(), 313 | Modifiers::Rotate => self.rotate(), 314 | Modifiers::Reverse => self.reverse(), 315 | Modifiers::XorAdd => self.xor_add() 316 | }, 317 | None => break 318 | } 319 | } 320 | 321 | general_purpose::STANDARD.encode(&self.data) 322 | } 323 | } 324 | 325 | fn extract_range(parts: &Vec<&str>, i: usize) -> Vec { 326 | // wC[H4.substr(1209, 5)](30, 52).length => [30, 52] 327 | let start_index = parts[i].find(']').unwrap() + 2; 328 | let substr = &parts[i][start_index..]; 329 | let end_index = substr.find(')').unwrap(); 330 | (&parts[i][start_index..start_index + end_index]).split(",").map(|x| x.parse().unwrap()).collect() 331 | } 332 | 333 | fn extract_rotate_index(parts: &Vec<&str>, i: usize) -> usize { 334 | let end = parts[i].rfind("])%").unwrap(); 335 | let start = parts[i].rfind("[").unwrap(); 336 | (&parts[i][start + 1..end]).parse().unwrap() 337 | } 338 | 339 | fn extract_l_r_shift_index(parts: &Vec<&str>, i: usize) -> usize { 340 | let start = parts[i].find('[').unwrap() + 1; 341 | let end = parts[i].find(']').unwrap(); 342 | (&parts[i][start..end]).parse().unwrap() 343 | } 344 | 345 | fn init_encoder(parts: &Vec<&str>, index: usize, session_seed: u64) -> Encoder { 346 | 347 | let iter_exp = parts[index]; 348 | let seed_exp = parts[index - 3]; 349 | 350 | let iter_start = iter_exp.find('<').unwrap() + 1; 351 | let iter_end = iter_exp.find(')').unwrap(); 352 | let iterations: u8 = (&iter_exp[iter_start..iter_end]).parse().unwrap(); 353 | 354 | let seed_start = seed_exp.rfind('(').unwrap() + 1; 355 | let seed_end = seed_exp.rfind(',').unwrap(); 356 | let seed: u64 = (&seed_exp[seed_start..seed_end]).parse().unwrap(); 357 | 358 | Encoder::new(seed, session_seed, iterations) 359 | } 360 | 361 | fn extract_modifiers(parts: &Vec<&str>, mut i: usize, encoder: &mut Encoder) -> usize { 362 | 363 | // Skip anything between encoder init and modifications 364 | while parts[i].len() > 60 || !parts[i].starts_with("var ") || !parts[i].contains(".replace") { 365 | i += 1; 366 | } 367 | 368 | i += 4; // Skip data -> bytes conversion 369 | 370 | // Check all expressions until data is base64 encoded 371 | while !parts[i].contains("window.btoa") { 372 | 373 | i += 1; 374 | 375 | // All modifiers start with while so ignore if false 376 | if !parts[i].starts_with("while") { 377 | continue; 378 | } 379 | 380 | if parts[i].contains("+1<") { 381 | encoder.add_step(Modifiers::Switch); 382 | } 383 | else if parts[i].contains(">=0") { 384 | encoder.add_step(Modifiers::Reverse); 385 | } 386 | else if parts[i].contains(">>8") { 387 | let index = extract_l_r_shift_index(parts, i - 3); 388 | encoder.add_l_r_shift_index(index); 389 | encoder.add_step(Modifiers::LRShift); 390 | } 391 | else if parts[i].contains(".push") { 392 | if parts[i].contains("])%") { 393 | let index = extract_rotate_index(parts, i); 394 | encoder.add_rotate_index(index); 395 | encoder.add_step(Modifiers::Rotate); 396 | } else { 397 | let positions = extract_range(parts, i - 3); 398 | encoder.set_include_encode_arr_values(positions[0], positions[1]); 399 | encoder.add_step(Modifiers::IncludeEncArr); 400 | } 401 | } 402 | else if parts[i].contains("var") { 403 | if parts[i + 1].contains("&127") { 404 | let positions = extract_range(parts, i - 3); 405 | encoder.add_xor_add_values(positions[0], positions[1]); 406 | encoder.add_step(Modifiers::XorAdd); 407 | } else { 408 | let value: u8 = (&parts[i - 2][parts[i - 2].find('=').unwrap() + 1..]).parse().unwrap(); 409 | let positions = extract_range(parts, i - 4); 410 | encoder.add_triple_xor_values(value, positions[0], positions[1]); 411 | encoder.add_step(Modifiers::TripleXor); 412 | } 413 | } 414 | else {println!("UNKNOWN PART: {}", parts[i]);} 415 | } 416 | return i; 417 | } 418 | 419 | pub struct Encoders<'a> { 420 | encoder: Vec, 421 | index_mapper: &'a HashMap 422 | } 423 | 424 | impl<'a> Encoders<'a> { 425 | pub fn empty() -> Self { 426 | Self { 427 | encoder: Vec::new(), 428 | index_mapper: &DEFAULT_ENCODER_INDICES 429 | } 430 | } 431 | pub fn get_id(&self, encode_type: EncoderIndices) -> u64 { 432 | let encoder_index = self.index_mapper.get(&encode_type).unwrap(); 433 | self.encoder[*encoder_index]._id 434 | } 435 | pub fn encode(&mut self, encode_type: EncoderIndices, data: impl Encodable) -> String { 436 | let encoder_index = self.index_mapper.get(&encode_type).unwrap(); 437 | self.encoder[*encoder_index].encode(data) 438 | } 439 | } 440 | 441 | fn handle_nested_encoder(parts: &Vec<&str>, mut i: usize, session_seed: u64) -> usize { 442 | let mut encoder = init_encoder(parts, i, session_seed); 443 | i = extract_modifiers(&parts, i, &mut encoder); 444 | 445 | i 446 | } 447 | 448 | pub fn assemble_encoders(script: &str, session_seed: u64, is_waf: bool) -> Encoders<'_> { 449 | let parts: Vec<&str> = script.split(";").collect(); 450 | 451 | let mut encoders: Vec = Vec::new(); 452 | 453 | for mut i in 0..parts.len() { 454 | 455 | if 456 | !parts[i].starts_with("while") || 457 | !parts[i].contains("()&255") {continue;} 458 | 459 | let encoder_index = encoders.len(); 460 | let encoder = init_encoder(&parts, i, session_seed); 461 | 462 | encoders.push(encoder); 463 | 464 | i += 1; 465 | 466 | loop { 467 | let part = parts[i]; 468 | 469 | if !(part.len() > 60 || !part.starts_with("var ") || !part.contains(".replace")) { 470 | break 471 | } 472 | 473 | if part.starts_with("while") && part.contains("()&255") { 474 | i = handle_nested_encoder(&parts, i, session_seed); 475 | } 476 | i += 1; 477 | } 478 | 479 | extract_modifiers(&parts, i, &mut encoders[encoder_index]); 480 | 481 | } 482 | 483 | Encoders { 484 | encoder: encoders, 485 | index_mapper: if is_waf { &WAF_ENCODER_INDICES } else { &DEFAULT_ENCODER_INDICES } 486 | } 487 | } -------------------------------------------------------------------------------- /src/enums.rs: -------------------------------------------------------------------------------- 1 | extern crate enum_index; 2 | 3 | #[derive(EnumIndex, IndexEnum, Debug, Clone, Hash, Eq, PartialEq)] 4 | pub enum MainIndices { 5 | Telemetry, 6 | BasDetection, 7 | SiteKey, 8 | StaticNum, 9 | ScriptLoadTime, 10 | ScriptInterrogationCounter, 11 | Slc, 12 | Gcs, 13 | PropertyChecks, 14 | UserAgent, 15 | Language, 16 | Languages, 17 | Timings, 18 | MimeTypes, 19 | Screen, 20 | TimezoneOffset, 21 | IndexedDb, 22 | AddBehavior, 23 | OpenDatabase, 24 | CpuClass, 25 | Platform, 26 | DoNotTrack, 27 | PluginList, 28 | PluginFunctions, 29 | Canvas, 30 | Image, 31 | WebGL, 32 | SmallImage, 33 | WebGLPrototypes, 34 | TouchData, 35 | VideoChecks, 36 | AudioChecks, 37 | Vendor, 38 | Product, 39 | ProductSub, 40 | ChromeProperties, 41 | RandomProperties, 42 | Protocol, 43 | Fonts, 44 | Scripts, 45 | ExecutedFunctions, 46 | WindowPropertyDescriptors, 47 | BrowserOnEvents, 48 | Window30PropertyNames, 49 | VisualViewport, 50 | HtmlCreateFunctionNames, 51 | HighSurrogate, 52 | SkipReeseExpiration, 53 | WafAlwaysTrue, 54 | WorkerIsFunction, 55 | WebAssemblyIsObject, 56 | CreatedDivs, 57 | TypeofChecks, 58 | NavigatorPropertyChecks, 59 | Checksum, 60 | VersionState, 61 | VersionNum, 62 | SessionStr 63 | } 64 | 65 | pub enum SubkeyIndices { 66 | Telemetry = 2, 67 | Languages = 9, 68 | Timings = 10, 69 | MimeTypes = 11, 70 | Screen = 12, 71 | PluginFunctions = 13, 72 | Canvas = 14, 73 | Image = 0, 74 | WebGL = 16, 75 | WebGLPrototypes = 18, 76 | TouchData = 19, 77 | VideoChecks = 20, 78 | AudioChecks = 21, 79 | ChromeProperties = 22, 80 | RandomProperties = 24, 81 | Protocol = 26, 82 | Scripts = 27, 83 | ExecutedFunctions = 28, 84 | VisualViewport = 29, 85 | CreatedDivs = 30, 86 | TypeofChecks = 31 87 | } 88 | 89 | pub enum ExtrakeyIndices { 90 | ChromeProperties = 23, 91 | RandomProperties = 25, 92 | TypeofChecks = 1 93 | } 94 | 95 | #[derive(Debug, Clone, Hash, Eq, PartialEq)] 96 | pub enum EncoderIndices { 97 | TypeofChecks, 98 | StaticNum, 99 | ScriptLoadTime, 100 | ScriptInterrogationCounter, 101 | Slc, 102 | Gcs, 103 | Timings, 104 | CurrentUnix, 105 | CurrentUnix2, 106 | Performance, 107 | Timeline, 108 | StartUnix, 109 | MimeTypes, 110 | MimeTypesSub, 111 | Screen, 112 | Canvas, 113 | CanvasHash, 114 | Image, 115 | WebGL, 116 | WebGLHash, 117 | SmallImage, 118 | TouchData, 119 | VideoChecks, 120 | AudioChecks, 121 | ChromeProperties, 122 | RandomProperties, 123 | ExecutedFunctions, 124 | BrowserOnEvents, 125 | WindowPropertyDescriptors, 126 | Window30PropertyNames, 127 | VisualViewport, 128 | HtmlCreateFunctionNames, 129 | HighSurrogate, 130 | CreatedDivs, 131 | NavigatorPropertyChecks, 132 | Checksum, 133 | VersionState, 134 | VersionNum, 135 | SessionStr, 136 | Payload, 137 | } 138 | 139 | //impl std::ops::Index for EncoderIndices { 140 | // 141 | //} -------------------------------------------------------------------------------- /src/extract.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | use anyhow::Result; 3 | 4 | use crate::utils::substr; 5 | 6 | const SITEKEY_OFFSET: [f64; 2] = [0.01, 0.12]; 7 | const VERSION_NUM_OFFSET: [f64; 2] = [0.91, 0.98]; 8 | const DYNAMIC_FUNC_STR_OFFSET: [f64; 2] = [0.74, 0.8]; 9 | const NAVIGATOR_PROPERTY_KEYS_OFFSET: [f64; 2] = [0.84, 0.95]; 10 | const DIV_PROPERTY_KEYS_OFFSET: [f64; 2] = [0.82, 0.95]; 11 | const PAYLOAD_KEYS_OFFSET: [f64; 2] = [0.125, 1.0]; 12 | 13 | #[derive(Default, Clone)] 14 | pub struct Extractor { 15 | pub st: u64, 16 | pub sr: u64, 17 | pub checksum_arr: Vec, 18 | 19 | pub keys_map: HashMap>, 20 | pub keys_order: Vec, 21 | 22 | pub sitekey: String, 23 | 24 | pub version_num_str: String, 25 | pub session_str: String, 26 | 27 | pub div_property_keys: Vec, 28 | pub dynamic_func_str: String, 29 | 30 | pub navigator_property_keys: Vec, 31 | pub navigator_property_value: String 32 | } 33 | 34 | impl Extractor { 35 | pub fn new() -> Self { 36 | Self { 37 | ..Default::default() 38 | } 39 | } 40 | 41 | const ST_SR_SKIP_FROM_RIGHT: usize = 300; 42 | 43 | fn extract_st_sr(&mut self, script: &str) { 44 | let offset = script[..script.len() - Self::ST_SR_SKIP_FROM_RIGHT].rfind("window.btoa").unwrap(); 45 | let mut snippet = &script[offset..script.len() - Self::ST_SR_SKIP_FROM_RIGHT]; // 300 is offset to latest pos to extract sr and st easily 46 | 47 | let chars_to_skip = snippet.find('=').unwrap() + 1; 48 | snippet = &snippet[chars_to_skip+1..]; 49 | 50 | let st_start = snippet.find('=').unwrap() + 1; 51 | let st_end = st_start + snippet[st_start..].find(';').unwrap(); 52 | let st = &snippet[st_start..st_end]; 53 | snippet = &snippet[st_end..]; 54 | 55 | let sr_start = snippet.find('=').unwrap() + 1; 56 | let sr_end = sr_start + snippet[sr_start..].find(';').unwrap(); 57 | let sr = &snippet[sr_start..sr_end]; 58 | 59 | self.st = st.parse().unwrap(); 60 | self.sr = sr.parse().unwrap(); 61 | } 62 | 63 | fn extract_checksum_arr(&mut self, script: &str) { 64 | let offset = script.find("0^-1").unwrap(); 65 | let snippet = &script[offset..]; 66 | let start = snippet.find('[').unwrap() + 1; 67 | let end = snippet.find(']').unwrap(); 68 | let arr: Vec = snippet[start..end].split(',').map(|x| x.parse().unwrap()).collect(); 69 | 70 | self.checksum_arr = arr 71 | } 72 | 73 | pub fn extract_payload_keys(&mut self, script: &str) { 74 | 75 | let pieces: Vec<&str> = substr(script, PAYLOAD_KEYS_OFFSET).split(|c| c == '"' || c == '.' || c == ';' || c == ' ').collect(); 76 | 77 | for i in 1..pieces.len() - 1 { 78 | let piece = pieces[i]; 79 | let prev = pieces[i - 1]; 80 | let next = pieces[i + 1]; 81 | if prev.ends_with("[") && next.starts_with("]") { 82 | let offset = prev[0..prev.len()-1] 83 | .rfind(|c| c != '_' && !char::is_alphanumeric(c)) 84 | .unwrap_or_else(||usize::MAX); 85 | let id = if offset == usize::MAX { 86 | prev[0..prev.len() - 1].to_string() 87 | } else { 88 | prev[offset + 1..prev.len() - 1].to_string() 89 | }; 90 | let property = piece; 91 | //println!("{} -> {}", pieces[i - 1], id); 92 | if !self.keys_order.contains(&id) { 93 | self.keys_order.push(id.clone()) 94 | }; 95 | self.keys_map.entry(id) 96 | .or_insert_with(Vec::new) 97 | .push(property.to_string()); 98 | } 99 | else if piece.len() > 6 && pieces[i].contains("=") && !pieces[i - 1].ends_with("var") { 100 | 101 | //if piece.contains("Bl_nKzEp") { 102 | // let offset = pieces[i - 1].rfind(|c| c != '_' && !char::is_alphanumeric(c)).unwrap_or_else(||usize::MAX); 103 | // let key = if offset == usize::MAX { 104 | // (&pieces[i - 1]).to_string() 105 | // } else { 106 | // (&pieces[i - 1][offset + 1..]).to_string() 107 | // }; 108 | // panic!("{key}"); 109 | //} 110 | 111 | //let offset = pieces[i - 1].rfind(char::is_alphanumeric).unwrap_or_else(||1); 112 | //if offset == 0 {continue}; 113 | //let key = &pieces[i - 1][offset - 1..]; 114 | 115 | let offset = pieces[i - 1].rfind(|c| c != '_' && !char::is_alphanumeric(c)).unwrap_or_else(||usize::MAX); 116 | let key = if offset == usize::MAX { 117 | (&pieces[i - 1]).to_string() 118 | } else { 119 | (&pieces[i - 1][offset + 1..]).to_string() 120 | }; 121 | 122 | if key.len() < 2 || !key.chars().all(|c| c == '_' || char::is_alphanumeric(c)) {continue}; 123 | let equal_sign_pos = pieces[i].rfind('=').unwrap(); 124 | let property = &pieces[i][0..equal_sign_pos]; 125 | if property.len() % 4 != 0 || !property.chars().all(|c| c == '_' || char::is_alphanumeric(c)) {continue}; 126 | //println!("{} -> {}", pieces[i - 1], key); 127 | if !self.keys_order.contains(&key) {self.keys_order.push(key.clone())}; 128 | self.keys_map.entry(key) 129 | .or_insert_with(Vec::new) 130 | .push(property.to_string()); 131 | //lengths.insert(length); 132 | } 133 | } 134 | 135 | for (_, value) in self.keys_map.iter_mut() { 136 | let mut seen: HashSet<&str> = HashSet::new(); 137 | let mut result: Vec = Vec::new(); 138 | for item in value.iter() { 139 | if seen.insert(item) { 140 | result.push(item.to_string()); 141 | } 142 | } 143 | value.clear(); 144 | value.extend(result); 145 | } 146 | } 147 | 148 | fn extract_sitekey(&mut self, script: &str) { 149 | let offset = (script.len() as f64 * SITEKEY_OFFSET[0]) as usize; 150 | let start = script[offset..].find("aih").unwrap(); 151 | let end = script[offset + start..].find("',").unwrap(); 152 | let index = offset + start; 153 | let sitekey = &script[index + 6..index + end]; 154 | 155 | self.sitekey = sitekey.into(); 156 | } 157 | 158 | fn extract_version_and_session_string(&mut self, script: &str) { 159 | let test: Vec<&str> = substr(script, VERSION_NUM_OFFSET).split(";").collect(); 160 | for line in test { 161 | if line.contains("JSON") && line.contains("window.JSON.stringify(\"") && !line.contains("\"beta\"") && !line.contains("\"stable\"") { 162 | if self.version_num_str.is_empty() { 163 | self.version_num_str = line.split("\"") 164 | .nth(1) 165 | .unwrap() 166 | .to_string(); 167 | } else { 168 | self.session_str = line.split("\"") 169 | .nth(1) 170 | .unwrap() 171 | .to_string(); 172 | return 173 | } 174 | } 175 | } 176 | panic!("Version and session string"); 177 | } 178 | 179 | fn extract_div_property_keys(&mut self, script: &str) { 180 | let test: Vec<&str> = substr(script, DIV_PROPERTY_KEYS_OFFSET).split("var").collect(); 181 | for line in test { 182 | if line.contains("[[\"") && line.matches("],[").count() == 5 { 183 | let test: Vec = line 184 | .split("\"") 185 | .skip(1) 186 | .step_by(2) 187 | .map(String::from) 188 | .collect(); 189 | self.div_property_keys = test; 190 | return // (keys, value) 191 | } 192 | } 193 | panic!("extract_div_keys"); 194 | } 195 | 196 | fn extract_dynamic_func_string(&mut self, script: &str) { 197 | let test: Vec<&str> = substr(script, DYNAMIC_FUNC_STR_OFFSET).split(";").collect(); 198 | for line in test { 199 | if line.contains("var") && line.contains("\"+") { 200 | self.dynamic_func_str = line.split("\"") 201 | .nth(1) 202 | .unwrap() 203 | .to_string(); 204 | return 205 | } 206 | } 207 | panic!("extract_dynamic_func_string"); 208 | } 209 | 210 | fn extract_navigator_property_keys(&mut self, script: &str) { 211 | let test: Vec<&str> = substr(script, NAVIGATOR_PROPERTY_KEYS_OFFSET).split("try{").collect(); 212 | for line in test { 213 | if line.contains("in [[\"") { 214 | let test: Vec = line 215 | .split("\"") 216 | .skip(1) 217 | .step_by(2) 218 | .map(String::from) 219 | .collect(); 220 | let len: usize = test.len(); 221 | let count: usize = (test.len() - 2) / 3; 222 | self.navigator_property_value = (test[len - 2]).to_string(); // by 3 cause the whole block is present 3 times + the 2 other values (non-keys) 223 | self.navigator_property_keys = (&test[..count]).to_vec(); 224 | return; 225 | } 226 | } 227 | panic!("extract_navigator_property_keys"); 228 | } 229 | 230 | pub fn extract(&mut self, dynamic_script: &str, static_script: &str) -> Result<()> { 231 | self.extract_st_sr(dynamic_script); 232 | self.extract_checksum_arr(dynamic_script); 233 | self.extract_payload_keys(dynamic_script); 234 | self.extract_sitekey(static_script); 235 | 236 | self.extract_version_and_session_string(dynamic_script); 237 | self.extract_div_property_keys(dynamic_script); 238 | self.extract_dynamic_func_string(dynamic_script); 239 | self.extract_navigator_property_keys(dynamic_script); 240 | 241 | Ok(()) 242 | } 243 | } -------------------------------------------------------------------------------- /src/keys.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use once_cell::sync::Lazy; 4 | 5 | use crate::enums::{EncoderIndices, MainIndices as MainIndices}; 6 | 7 | pub static DEFAULT_MAIN_KEY_INDICES: Lazy> = Lazy::new(|| { 8 | HashMap::from([ 9 | (MainIndices::Telemetry, 0), 10 | (MainIndices::BasDetection, 1), 11 | (MainIndices::SiteKey, 2), 12 | (MainIndices::StaticNum, 3), 13 | (MainIndices::ScriptLoadTime, 4), 14 | (MainIndices::ScriptInterrogationCounter, 5), 15 | (MainIndices::Slc, 6), 16 | (MainIndices::Gcs, 7), 17 | (MainIndices::PropertyChecks, 8), 18 | (MainIndices::UserAgent, 9), 19 | (MainIndices::Language, 10), 20 | (MainIndices::Languages, 11), 21 | (MainIndices::Timings, 13), 22 | (MainIndices::MimeTypes, 14), 23 | (MainIndices::Screen, 15), 24 | (MainIndices::TimezoneOffset, 16), 25 | (MainIndices::IndexedDb, 17), 26 | (MainIndices::AddBehavior, 18), 27 | (MainIndices::OpenDatabase, 19), 28 | (MainIndices::CpuClass, 20), 29 | (MainIndices::Platform, 21), 30 | (MainIndices::DoNotTrack, 22), 31 | (MainIndices::PluginList, 23), 32 | (MainIndices::PluginFunctions, 24), 33 | (MainIndices::Canvas, 25), 34 | (MainIndices::Image, 26), 35 | (MainIndices::WebGL, 27), 36 | (MainIndices::SmallImage, 28), 37 | (MainIndices::WebGLPrototypes, 29), 38 | (MainIndices::TouchData, 30), 39 | (MainIndices::VideoChecks, 31), 40 | (MainIndices::AudioChecks, 32), 41 | (MainIndices::Vendor, 33), 42 | (MainIndices::Product, 34), 43 | (MainIndices::ProductSub, 35), 44 | (MainIndices::ChromeProperties, 36), 45 | (MainIndices::RandomProperties, 37), 46 | (MainIndices::Protocol, 38), 47 | (MainIndices::Fonts, 39), 48 | (MainIndices::Scripts, 40), 49 | (MainIndices::ExecutedFunctions, 41), 50 | (MainIndices::WindowPropertyDescriptors, 42), 51 | (MainIndices::BrowserOnEvents, 43), 52 | (MainIndices::Window30PropertyNames, 44), 53 | (MainIndices::VisualViewport, 45), 54 | (MainIndices::HtmlCreateFunctionNames, 46), 55 | (MainIndices::HighSurrogate, 47), 56 | (MainIndices::SkipReeseExpiration, 48), 57 | (MainIndices::WorkerIsFunction, 49), 58 | (MainIndices::WebAssemblyIsObject, 50), 59 | (MainIndices::CreatedDivs, 51), 60 | (MainIndices::TypeofChecks, 52), 61 | (MainIndices::NavigatorPropertyChecks, 54), 62 | (MainIndices::Checksum, 55), 63 | (MainIndices::VersionState, 56), 64 | (MainIndices::VersionNum, 57), 65 | (MainIndices::SessionStr, 58) 66 | ]) 67 | }); 68 | 69 | pub static DEFAULT_ENCODER_INDICES: Lazy> = Lazy::new(|| { 70 | HashMap::from([ 71 | (EncoderIndices::TypeofChecks, 1), 72 | (EncoderIndices::StaticNum, 11), 73 | (EncoderIndices::ScriptLoadTime, 12), 74 | (EncoderIndices::ScriptInterrogationCounter, 13), 75 | (EncoderIndices::Slc, 14), 76 | (EncoderIndices::Gcs, 15), 77 | (EncoderIndices::Timings, 17), 78 | (EncoderIndices::CurrentUnix, 18), 79 | (EncoderIndices::CurrentUnix2, 19), 80 | (EncoderIndices::Performance, 20), 81 | (EncoderIndices::Timeline, 21), 82 | (EncoderIndices::StartUnix, 22), 83 | (EncoderIndices::MimeTypes, 23), 84 | (EncoderIndices::MimeTypesSub, 24), 85 | (EncoderIndices::Screen, 25), 86 | (EncoderIndices::Canvas, 26), 87 | (EncoderIndices::CanvasHash, 27), 88 | (EncoderIndices::Image, 28), 89 | (EncoderIndices::WebGL, 29), 90 | (EncoderIndices::WebGLHash, 30), 91 | (EncoderIndices::SmallImage, 31), 92 | (EncoderIndices::TouchData, 32), 93 | (EncoderIndices::VideoChecks, 33), 94 | (EncoderIndices::AudioChecks, 34), 95 | (EncoderIndices::ChromeProperties, 35), 96 | (EncoderIndices::RandomProperties, 36), 97 | (EncoderIndices::ExecutedFunctions, 37), 98 | (EncoderIndices::BrowserOnEvents, 38), 99 | (EncoderIndices::WindowPropertyDescriptors, 39), 100 | (EncoderIndices::Window30PropertyNames, 40), 101 | (EncoderIndices::VisualViewport, 41), 102 | (EncoderIndices::HtmlCreateFunctionNames, 42), 103 | (EncoderIndices::HighSurrogate, 43), 104 | (EncoderIndices::CreatedDivs, 44), 105 | (EncoderIndices::NavigatorPropertyChecks, 47), 106 | (EncoderIndices::Checksum, 48), 107 | (EncoderIndices::VersionState, 49), 108 | (EncoderIndices::VersionNum, 50), 109 | (EncoderIndices::SessionStr, 51), 110 | (EncoderIndices::Payload, 53), 111 | ]) 112 | }); 113 | 114 | pub static WAF_MAIN_KEY_INDICES: Lazy> = Lazy::new(|| { 115 | HashMap::from([ 116 | (MainIndices::Telemetry, 0), 117 | (MainIndices::BasDetection, 1), 118 | (MainIndices::SiteKey, 2), 119 | (MainIndices::StaticNum, 3), 120 | (MainIndices::ScriptLoadTime, 4), 121 | (MainIndices::ScriptInterrogationCounter, 5), 122 | (MainIndices::Slc, 6), 123 | (MainIndices::Gcs, 7), 124 | (MainIndices::PropertyChecks, 8), 125 | (MainIndices::UserAgent, 9), 126 | (MainIndices::Language, 10), 127 | (MainIndices::Languages, 11), 128 | (MainIndices::Timings, 13), 129 | (MainIndices::MimeTypes, 14), 130 | (MainIndices::Screen, 15), 131 | (MainIndices::TimezoneOffset, 16), 132 | (MainIndices::IndexedDb, 17), 133 | (MainIndices::AddBehavior, 18), 134 | (MainIndices::OpenDatabase, 19), 135 | (MainIndices::CpuClass, 20), 136 | (MainIndices::Platform, 21), 137 | (MainIndices::DoNotTrack, 22), 138 | (MainIndices::PluginList, 23), 139 | (MainIndices::PluginFunctions, 24), 140 | (MainIndices::Canvas, 25), 141 | (MainIndices::Image, 26), 142 | (MainIndices::WebGL, 27), 143 | (MainIndices::SmallImage, 28), 144 | (MainIndices::WebGLPrototypes, 29), 145 | (MainIndices::TouchData, 30), 146 | (MainIndices::VideoChecks, 31), 147 | (MainIndices::AudioChecks, 32), 148 | (MainIndices::Vendor, 33), 149 | (MainIndices::Product, 34), 150 | (MainIndices::ProductSub, 35), 151 | (MainIndices::ChromeProperties, 36), 152 | (MainIndices::RandomProperties, 37), 153 | (MainIndices::Protocol, 38), 154 | (MainIndices::Fonts, 39), 155 | (MainIndices::Scripts, 40), 156 | (MainIndices::ExecutedFunctions, 41), 157 | (MainIndices::WindowPropertyDescriptors, 42), 158 | (MainIndices::BrowserOnEvents, 43), 159 | (MainIndices::Window30PropertyNames, 44), 160 | (MainIndices::VisualViewport, 45), 161 | (MainIndices::HtmlCreateFunctionNames, 46), 162 | (MainIndices::HighSurrogate, 47), 163 | (MainIndices::SkipReeseExpiration, 48), 164 | (MainIndices::WafAlwaysTrue, 49), 165 | (MainIndices::WorkerIsFunction, 50), 166 | (MainIndices::WebAssemblyIsObject, 51), 167 | (MainIndices::CreatedDivs, 52), 168 | (MainIndices::TypeofChecks, 53), 169 | (MainIndices::NavigatorPropertyChecks, 55), 170 | (MainIndices::Checksum, 56), 171 | (MainIndices::VersionState, 57), 172 | (MainIndices::VersionNum, 58), 173 | (MainIndices::SessionStr, 59) 174 | ]) 175 | }); 176 | 177 | pub static WAF_ENCODER_INDICES: Lazy> = Lazy::new(|| { 178 | HashMap::from([ 179 | (EncoderIndices::TypeofChecks, 1), 180 | (EncoderIndices::StaticNum, 11), 181 | (EncoderIndices::ScriptLoadTime, 12), 182 | (EncoderIndices::ScriptInterrogationCounter, 13), 183 | (EncoderIndices::Slc, 14), 184 | (EncoderIndices::Gcs, 15), 185 | (EncoderIndices::Timings, 17), 186 | (EncoderIndices::CurrentUnix, 18), 187 | (EncoderIndices::CurrentUnix2, 19), 188 | (EncoderIndices::Performance, 20), 189 | (EncoderIndices::Timeline, 21), 190 | (EncoderIndices::StartUnix, 22), 191 | (EncoderIndices::MimeTypes, 23), 192 | (EncoderIndices::MimeTypesSub, 24), 193 | (EncoderIndices::Screen, 25), 194 | (EncoderIndices::Canvas, 26), 195 | (EncoderIndices::CanvasHash, 27), 196 | (EncoderIndices::Image, 28), 197 | (EncoderIndices::WebGL, 29), 198 | (EncoderIndices::WebGLHash, 30), 199 | (EncoderIndices::SmallImage, 31), 200 | (EncoderIndices::TouchData, 32), 201 | (EncoderIndices::VideoChecks, 33), 202 | (EncoderIndices::AudioChecks, 34), 203 | (EncoderIndices::ChromeProperties, 35), 204 | (EncoderIndices::RandomProperties, 36), 205 | (EncoderIndices::ExecutedFunctions, 37), 206 | (EncoderIndices::BrowserOnEvents, 38), 207 | (EncoderIndices::WindowPropertyDescriptors, 39), 208 | (EncoderIndices::Window30PropertyNames, 40), 209 | (EncoderIndices::VisualViewport, 41), 210 | (EncoderIndices::HtmlCreateFunctionNames, 42), 211 | (EncoderIndices::HighSurrogate, 43), 212 | (EncoderIndices::CreatedDivs, 44), 213 | (EncoderIndices::NavigatorPropertyChecks, 47), 214 | (EncoderIndices::Checksum, 48), 215 | (EncoderIndices::VersionState, 49), 216 | (EncoderIndices::VersionNum, 50), 217 | (EncoderIndices::SessionStr, 51), 218 | (EncoderIndices::Payload, 53), 219 | ]) 220 | }); -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate enum_index_derive; 3 | 4 | pub mod reese; 5 | mod encoder; 6 | mod extract; 7 | mod payload; 8 | mod utils; 9 | mod enums; 10 | mod device; 11 | //mod cache; 12 | mod keys; -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use reese84::reese::{solve_reese, solve_reese_catching}; 4 | 5 | #[tokio::main] 6 | async fn main() { 7 | 8 | std::env::set_var("DEBUG", "1".to_string()); 9 | 10 | let script = std::fs::read_to_string("./debug/script.js").unwrap(); 11 | solve_reese(script.clone(), "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36".into()).unwrap(); 12 | 13 | if std::env::args().any(|arg| arg.as_str() == "bench") { 14 | let count = 15000; 15 | let scripts = (0..count).map(|_| script.clone()).collect::>(); 16 | 17 | let start = Instant::now(); 18 | let mut handles = vec![]; 19 | let mut per_instance = vec![]; 20 | 21 | for script in scripts { 22 | let handle = tokio::task::spawn(async { 23 | let start = Instant::now(); 24 | let _ = solve_reese_catching(script, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36".into()).await; 25 | start.elapsed().as_micros() 26 | }); 27 | handles.push(handle) 28 | } 29 | 30 | 31 | for handle in handles { 32 | let elapsed = handle.await.unwrap(); 33 | per_instance.push(elapsed); 34 | } 35 | 36 | /* 37 | # start 38 | total: 2871 ms 39 | avg: 3059 micros 40 | 41 | # no unwraps 42 | total: 4381 ms 43 | avg: 4670 micros 44 | 45 | */ 46 | 47 | println!("total: {} ms", (start.elapsed().as_millis())); 48 | println!("avg: {} micros", per_instance.iter().map(|x| *x).sum::() / per_instance.len() as u128); 49 | } 50 | } -------------------------------------------------------------------------------- /src/payload.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use enum_index::IndexEnum; 4 | use serde_json::{json, Value}; 5 | use rand::Rng; 6 | 7 | use crate::keys::{DEFAULT_MAIN_KEY_INDICES, WAF_MAIN_KEY_INDICES}; 8 | use crate::reese::ReeseSolver; 9 | use crate::utils::{calc_checksum, solve_dynamic_func, get_unix_ts}; 10 | use crate::enums::*; 11 | 12 | use crate::device::DEVICE; 13 | 14 | const MAIN_KEY_INDEX: usize = 7; 15 | 16 | trait ToValue { 17 | fn to_value(self) -> Value; 18 | } 19 | 20 | impl ToValue for &Value { 21 | fn to_value(self) -> Value { 22 | self.clone() 23 | } 24 | } 25 | 26 | impl ToValue for Value { 27 | fn to_value(self) -> Value { 28 | self 29 | } 30 | } 31 | 32 | impl ToValue for String { 33 | fn to_value(self) -> Value { 34 | self.into() 35 | } 36 | } 37 | 38 | impl ToValue for bool { 39 | fn to_value(self) -> Value { 40 | self.into() 41 | } 42 | } 43 | 44 | impl ToValue for &str { 45 | fn to_value(self) -> Value { 46 | self.into() 47 | } 48 | } 49 | 50 | 51 | 52 | #[derive(Clone)] 53 | struct Payload<'a> { 54 | keys: Vec, 55 | map: serde_json::Map, 56 | 57 | main_indices_mapper: &'a HashMap 58 | } 59 | 60 | impl<'a> Payload<'a> { 61 | fn new(keys: Vec, is_waf: bool) -> Self { 62 | Self { 63 | keys, 64 | map: serde_json::Map::new(), 65 | main_indices_mapper: if is_waf { &WAF_MAIN_KEY_INDICES } else { &DEFAULT_MAIN_KEY_INDICES } 66 | } 67 | } 68 | fn insert_main(&mut self, key_index: MainIndices, value: V) 69 | where 70 | V: ToValue, 71 | { 72 | let index = self.main_indices_mapper.get(&key_index).unwrap(); 73 | let key = self.keys.get(*index) 74 | .unwrap() 75 | .clone(); 76 | self.map.insert(key, value.to_value()); 77 | } 78 | fn insert(&mut self, key: K, value: V) 79 | where 80 | K: TryInto, 81 | V:ToValue, 82 | { 83 | let key = self.keys.get(key.try_into().ok().unwrap()) 84 | .unwrap() 85 | .clone(); 86 | self.map.insert(key, value.to_value()); 87 | } 88 | fn get(&self, key: &str) -> Option<&Value> { 89 | self.map.get(key) 90 | } 91 | fn keys(&self) -> Vec<&String> { 92 | self.map.keys().into_iter().collect() 93 | } 94 | fn to_string_pretty(&self) -> String { 95 | serde_json::to_string_pretty(&self.map).unwrap() 96 | } 97 | fn take(self) -> Value { 98 | self.map.into() 99 | } 100 | } 101 | 102 | pub fn gen_sensor(solver: &mut ReeseSolver) -> (serde_json::Value, String) { 103 | 104 | let extracted_data = &solver.extractor; 105 | 106 | let checksum = calc_checksum(&solver.seed.to_string(), extracted_data.sr.to_string(), &solver.user_agent, &solver.extractor.checksum_arr); 107 | 108 | let keys_map = &extracted_data.keys_map; 109 | let keys_order = &extracted_data.keys_order; 110 | let sitekey = &extracted_data.sitekey; 111 | let version_num_str = &extracted_data.version_num_str; 112 | let session_str = &extracted_data.session_str; 113 | let div_property_keys = &extracted_data.div_property_keys; 114 | let navigator_property_keys = &extracted_data.navigator_property_keys; 115 | let navigator_property_value = &extracted_data.navigator_property_value; 116 | 117 | let main_key_count = keys_map[&keys_order[MAIN_KEY_INDEX]].len(); 118 | solver.is_waf = match main_key_count { 119 | 60 => false, 120 | 61 => true, 121 | _ => panic!("Unknown main_key count {main_key_count}") 122 | }; 123 | 124 | let dynamic_func_res = solve_dynamic_func(solver.seed, &solver.extractor.dynamic_func_str); 125 | 126 | let telemetry_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Telemetry as usize]]; 127 | let telemetry = json!({ 128 | &telemetry_keys[0]: [], 129 | &telemetry_keys[1]: [], 130 | }); 131 | 132 | 133 | let languages_keys: &Vec = &extracted_data.keys_map[&extracted_data.keys_order[SubkeyIndices::Languages as usize]]; 134 | 135 | let languages = json!({ 136 | &languages_keys[0]: DEVICE["languages"]["disabled"], 137 | &languages_keys[1]: DEVICE["languages"]["list"], 138 | }); 139 | 140 | //let now: u128 = 100; // get_unix_ts(); 141 | //let performance: u128 = 100; // 600 + now % 300; 142 | //let timeline: u128 = 100; // performance - (5 + now % 3); 143 | //let start: u128 = 100; // now - (800 + now % 400); 144 | 145 | let mut rng = rand::thread_rng(); 146 | let random_float: f64 = rng.gen(); 147 | 148 | let now: u128 = get_unix_ts(); 149 | let performance: f64 = random_float * 300.0 + 600.0; 150 | let timeline: f64 = performance - random_float * 2.0 + 5.0; 151 | let start: f64 = now as f64 - random_float * 400.0; 152 | let timings_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Timings as usize]]; 153 | let timings = json!({ 154 | &timings_keys[0]: solver.encoders.encode(EncoderIndices::CurrentUnix, now.to_string()), 155 | &timings_keys[1]: solver.encoders.encode(EncoderIndices::CurrentUnix2, now.to_string()), 156 | &timings_keys[2]: solver.encoders.encode(EncoderIndices::Performance, performance.to_string()), // something wrong 157 | &timings_keys[3]: solver.encoders.encode(EncoderIndices::Timeline, format!("{:.3}", timeline)), 158 | &timings_keys[4]: solver.encoders.encode(EncoderIndices::StartUnix, start.to_string()), 159 | }); 160 | //println!("{}", serde_json::to_string_pretty(&timings).unwrap()); 161 | 162 | let mime_types_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::MimeTypes as usize]]; 163 | let mime_types: serde_json::Value = DEVICE["mime_types"].as_array().unwrap().iter().map(|mime_type| { 164 | let plain = mime_type[1].as_object().unwrap(); 165 | let data = json!({ 166 | &mime_types_keys[0]: plain["suffix"], 167 | &mime_types_keys[1]: plain["content_type"], 168 | &mime_types_keys[2]: plain["plugin_name"] 169 | }); 170 | return json!([mime_type[0], solver.encoders.encode(EncoderIndices::MimeTypesSub, data)]) 171 | }).collect(); 172 | 173 | 174 | let screen_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Screen as usize]]; 175 | let screen = json!({ 176 | &screen_keys[0]: DEVICE["screen"]["width"], 177 | &screen_keys[1]: DEVICE["screen"]["height"], 178 | &screen_keys[2]: DEVICE["screen"]["availHeight"], 179 | &screen_keys[3]: DEVICE["screen"]["availLeft"], 180 | &screen_keys[4]: DEVICE["screen"]["availTop"], 181 | &screen_keys[5]: DEVICE["screen"]["availWidth"], 182 | &screen_keys[6]: DEVICE["screen"]["pixelDepth"], 183 | &screen_keys[7]: DEVICE["screen"]["innerWidth"], 184 | &screen_keys[8]: DEVICE["screen"]["innerHeight"], 185 | &screen_keys[9]: DEVICE["screen"]["outerWidth"], 186 | &screen_keys[10]: DEVICE["screen"]["outerHeight"], 187 | &screen_keys[11]: DEVICE["screen"]["pixelRatio"], 188 | &screen_keys[12]: DEVICE["screen"]["orientation_type"], 189 | &screen_keys[13]: DEVICE["screen"]["screenX"], 190 | &screen_keys[14]: DEVICE["screen"]["screenY"] 191 | }); 192 | 193 | let plugin_functions_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::PluginFunctions as usize]]; 194 | let plugin_functions = json!({ 195 | &plugin_functions_keys[0]: DEVICE["plugin_functions_names"]["namedItem"], 196 | &plugin_functions_keys[1]: DEVICE["plugin_functions_names"]["item"], 197 | &plugin_functions_keys[2]: DEVICE["plugin_functions_names"]["refresh"] 198 | }); 199 | 200 | let web_gl_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::WebGL as usize]]; 201 | let canvas_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Canvas as usize]]; 202 | let canvas = json!({ 203 | &canvas_keys[0]: DEVICE["canvas"]["point_in_path"], 204 | &canvas_keys[1]: DEVICE["canvas"]["webp_format"], 205 | &canvas_keys[2]: DEVICE["canvas"]["globalCompositeOperation_is_screen"], 206 | &web_gl_keys[0]: solver.encoders.encode(EncoderIndices::CanvasHash, DEVICE["canvas"]["hash"].as_str().unwrap()) 207 | }); 208 | 209 | //println!("{}", serde_json::to_string_pretty(&canvas).unwrap()); 210 | //println!("{}", solver.encoders.encode(EncoderIndices::Canvas, canvas)); 211 | //println!("{:?}", solver.encoders[EncoderIndices::Canvas as usize].steps); 212 | //return json!({}); 213 | 214 | let image_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Image as usize]]; 215 | let image = json!({ 216 | &image_keys[1]: solver.encoders.encode(EncoderIndices::Image, DEVICE["image"]["dataURL"].as_str().unwrap()) 217 | }); 218 | 219 | let mut web_gl = Payload::new(web_gl_keys.clone(), false); 220 | web_gl.insert(0, solver.encoders.encode(EncoderIndices::WebGLHash, DEVICE["web_gl"]["hash"].as_str().unwrap())); 221 | web_gl.insert(2, &DEVICE["web_gl"]["supportedExtensions"]); 222 | web_gl.insert(3, &DEVICE["web_gl"]["line_width_range"]); 223 | web_gl.insert(4, &DEVICE["web_gl"]["point_size_range"]); 224 | web_gl.insert(5, &DEVICE["web_gl"]["alpha_bits"]); 225 | web_gl.insert(6, &DEVICE["web_gl"]["antialias"]); 226 | web_gl.insert(7, &DEVICE["web_gl"]["blue_bits"]); 227 | web_gl.insert(8, &DEVICE["web_gl"]["depth_bits"]); 228 | web_gl.insert(9, &DEVICE["web_gl"]["green_bits"]); 229 | web_gl.insert(10, &DEVICE["web_gl"]["max_anisotropy"]); 230 | web_gl.insert(11, &DEVICE["web_gl"]["max_combined_texture_image_units"]); 231 | web_gl.insert(12, &DEVICE["web_gl"]["max_cube_map_texture_size"]); 232 | web_gl.insert(13, &DEVICE["web_gl"]["max_fragment_uniform_vectors"]); 233 | web_gl.insert(14, &DEVICE["web_gl"]["max_renderbuffer_size"]); 234 | web_gl.insert(15, &DEVICE["web_gl"]["max_texture_image_units"]); 235 | web_gl.insert(16, &DEVICE["web_gl"]["max_texture_size"]); 236 | web_gl.insert(17, &DEVICE["web_gl"]["max_varying_vectors"]); 237 | web_gl.insert(18, &DEVICE["web_gl"]["max_vertex_attribs"]); 238 | web_gl.insert(19, &DEVICE["web_gl"]["max_vertex_texture_image_units"]); 239 | web_gl.insert(20, &DEVICE["web_gl"]["max_vertex_uniform_vectors"]); 240 | web_gl.insert(21, &DEVICE["web_gl"]["max_viewport_dims"]); 241 | web_gl.insert(22, &DEVICE["web_gl"]["red_bits"]); 242 | web_gl.insert(23, &DEVICE["web_gl"]["renderer"]); 243 | web_gl.insert(24, &DEVICE["web_gl"]["shading_language_version"]); 244 | web_gl.insert(25, &DEVICE["web_gl"]["stencil_bits"]); 245 | web_gl.insert(26, &DEVICE["web_gl"]["vendor"]); 246 | web_gl.insert(27, &DEVICE["web_gl"]["version"]); 247 | web_gl.insert(28, &DEVICE["web_gl"]["vertex_high_float_precision"]); 248 | web_gl.insert(29, &DEVICE["web_gl"]["vertex_high_float_rangeMin"]); 249 | web_gl.insert(30, &DEVICE["web_gl"]["vertex_high_float_rangeMax"]); 250 | web_gl.insert(31, &DEVICE["web_gl"]["vertex_medium_float_precision"]); 251 | web_gl.insert(32, &DEVICE["web_gl"]["vertex_medium_float_rangeMin"]); 252 | web_gl.insert(33, &DEVICE["web_gl"]["vertex_medium_float_rangeMax"]); 253 | web_gl.insert(34, &DEVICE["web_gl"]["vertex_low_float_precision"]); 254 | web_gl.insert(35, &DEVICE["web_gl"]["vertex_low_float_rangeMin"]); 255 | web_gl.insert(36, &DEVICE["web_gl"]["vertex_low_float_rangeMax"]); 256 | web_gl.insert(37, &DEVICE["web_gl"]["fragment_high_float_precision"]); 257 | web_gl.insert(38, &DEVICE["web_gl"]["fragment_high_float_rangeMin"]); 258 | web_gl.insert(39, &DEVICE["web_gl"]["fragment_high_float_rangeMax"]); 259 | web_gl.insert(40, &DEVICE["web_gl"]["fragment_medium_float_precision"]); 260 | web_gl.insert(41, &DEVICE["web_gl"]["fragment_medium_float_rangeMin"]); 261 | web_gl.insert(42, &DEVICE["web_gl"]["fragment_medium_float_rangeMax"]); 262 | web_gl.insert(43, &DEVICE["web_gl"]["fragment_low_float_precision"]); 263 | web_gl.insert(44, &DEVICE["web_gl"]["fragment_low_float_rangeMin"]); 264 | web_gl.insert(45, &DEVICE["web_gl"]["fragment_low_float_rangeMax"]); 265 | web_gl.insert(46, &DEVICE["web_gl"]["vertex_high_int_precision"]); 266 | web_gl.insert(47, &DEVICE["web_gl"]["vertex_high_int_rangeMin"]); 267 | web_gl.insert(48, &DEVICE["web_gl"]["vertex_high_int_rangeMax"]); 268 | web_gl.insert(49, &DEVICE["web_gl"]["vertex_medium_int_precision"]); 269 | web_gl.insert(50, &DEVICE["web_gl"]["vertex_medium_int_rangeMin"]); 270 | web_gl.insert(51, &DEVICE["web_gl"]["vertex_medium_int_rangeMax"]); 271 | web_gl.insert(52, &DEVICE["web_gl"]["vertex_low_int_precision"]); 272 | web_gl.insert(53, &DEVICE["web_gl"]["vertex_low_int_rangeMin"]); 273 | web_gl.insert(54, &DEVICE["web_gl"]["vertex_low_int_rangeMax"]); 274 | web_gl.insert(55, &DEVICE["web_gl"]["fragment_high_int_precision"]); 275 | web_gl.insert(56, &DEVICE["web_gl"]["fragment_high_int_rangeMin"]); 276 | web_gl.insert(57, &DEVICE["web_gl"]["fragment_high_int_rangeMax"]); 277 | web_gl.insert(58, &DEVICE["web_gl"]["fragment_medium_int_precision"]); 278 | web_gl.insert(59, &DEVICE["web_gl"]["fragment_medium_int_rangeMin"]); 279 | web_gl.insert(60, &DEVICE["web_gl"]["fragment_medium_int_rangeMax"]); 280 | web_gl.insert(61, &DEVICE["web_gl"]["fragment_low_int_precision"]); 281 | web_gl.insert(62, &DEVICE["web_gl"]["fragment_low_int_rangeMin"]); 282 | web_gl.insert(63, &DEVICE["web_gl"]["fragment_low_int_rangeMax"]); 283 | web_gl.insert(64, &DEVICE["web_gl"]["unmasked_vendor"]); 284 | web_gl.insert(65, &DEVICE["web_gl"]["unmasked_renderer"]); 285 | 286 | let web_gl = web_gl.take(); 287 | 288 | let small_image_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Image as usize]]; 289 | let small_image = json!({ 290 | &small_image_keys[1]: solver.encoders.encode(EncoderIndices::SmallImage, DEVICE["small_image"]["dataURL"].as_str().unwrap()) 291 | }); 292 | 293 | let web_gl_prototypes_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::WebGLPrototypes as usize]]; 294 | let web_gl_prototypes = json!({ 295 | &web_gl_prototypes_keys[0]: DEVICE["web_gl_prototypes"]["getParameter_name"], 296 | &web_gl_prototypes_keys[1]: DEVICE["web_gl_prototypes"]["getParameter_exists"] 297 | }); 298 | 299 | let touch_data_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::TouchData as usize]]; 300 | let touch_data = json!({ 301 | &touch_data_keys[0]: DEVICE["touch_data"]["maxTouchPoints"], 302 | &touch_data_keys[1]: DEVICE["touch_data"]["can_create_touchEvent"], 303 | &touch_data_keys[2]: DEVICE["touch_data"]["ontouchstart_unequal_undefined"] 304 | }); 305 | 306 | let video_checks_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::VideoChecks as usize]]; 307 | let video_checks = json!({ 308 | &video_checks_keys[0]: DEVICE["video_checks"]["can_play_ogg"], 309 | &video_checks_keys[1]: DEVICE["video_checks"]["can_play_mp4"], 310 | &video_checks_keys[2]: DEVICE["video_checks"]["can_play_webm"] 311 | }); 312 | 313 | let audio_checks_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::AudioChecks as usize]]; 314 | let audio_checks = json!({ 315 | &audio_checks_keys[0]: DEVICE["audio_checks"]["can_play_ogg"], 316 | &audio_checks_keys[1]: DEVICE["audio_checks"]["can_play_mpeg"], 317 | &audio_checks_keys[2]: DEVICE["audio_checks"]["can_play_wav"], 318 | &audio_checks_keys[3]: DEVICE["audio_checks"]["can_play_xm4a"], 319 | &audio_checks_keys[4]: DEVICE["audio_checks"]["can_play_empty"], 320 | &audio_checks_keys[5]: DEVICE["audio_checks"]["can_play_mp4"] 321 | }); 322 | 323 | let chrome_properties_extra_keys: &Vec = &keys_map[&keys_order[ExtrakeyIndices::ChromeProperties as usize]]; 324 | let chrome_properties_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::ChromeProperties as usize]]; 325 | let chrome_app_checks = json!({ 326 | &chrome_properties_keys[0]: DEVICE["chrome_properties"]["is_internet_explorer"], 327 | &chrome_properties_keys[1]: { 328 | &chrome_properties_extra_keys[0]: DEVICE["chrome_properties"]["chrome_app_checks"]["loadTimes_is_native"], 329 | &chrome_properties_extra_keys[1]: DEVICE["chrome_properties"]["chrome_app_checks"]["chrome_app_functions"], 330 | &chrome_properties_extra_keys[2]: DEVICE["chrome_properties"]["chrome_app_checks"]["chrome_app_properties"] 331 | }, 332 | &chrome_properties_keys[2]: DEVICE["chrome_properties"]["webdriver"], 333 | &chrome_properties_keys[3]: DEVICE["chrome_properties"]["is_chrome"], 334 | &chrome_properties_keys[4]: DEVICE["chrome_properties"]["connection_rtt"], 335 | &chrome_properties_keys[5]: DEVICE["chrome_properties"]["duckduckgo"] 336 | }); 337 | //println!("{}", serde_json::to_string_pretty(&chrome_app_checks).unwrap()); 338 | //println!("{}", solver.encoders[EncoderIndices::ChromeProperties]._id); 339 | 340 | let random_properties_extra_keys: &Vec = &keys_map[&keys_order[ExtrakeyIndices::RandomProperties as usize]]; 341 | let random_properties_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::RandomProperties as usize]]; 342 | let random_properties = json!({ 343 | &random_properties_keys[0]: DEVICE["random_properties"]["history_length"], 344 | &random_properties_keys[1]: DEVICE["random_properties"]["hardware_concurrency"], 345 | &random_properties_keys[2]: DEVICE["random_properties"]["top_unequal_self"], 346 | &random_properties_keys[3]: DEVICE["random_properties"]["getBattery_exists"], 347 | &random_properties_keys[4]: DEVICE["random_properties"]["console_debug_name"], 348 | &random_properties_keys[5]: DEVICE["random_properties"]["debug_exists"], 349 | &random_properties_keys[6]: DEVICE["random_properties"]["phantom"], 350 | &random_properties_keys[7]: DEVICE["random_properties"]["callPhantom"], 351 | &random_properties_keys[8]: DEVICE["random_properties"]["empty_array"], 352 | &random_properties_keys[9]: DEVICE["random_properties"]["window_presistent"], 353 | &random_properties_keys[10]: DEVICE["random_properties"]["window_temporary"], 354 | &random_properties_keys[11]: { 355 | &random_properties_extra_keys[0]: DEVICE["random_properties"]["performanceObserver"]["supportedEntryTypes"] 356 | }, 357 | &random_properties_keys[12]: DEVICE["random_properties"]["sentryInWindow"] 358 | }); 359 | //println!("{}", serde_json::to_string_pretty(&random_properties).unwrap()); 360 | 361 | let protocol_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Protocol as usize]]; 362 | let protocol = json!({ 363 | &protocol_keys[0]: DEVICE["protocol"]["location_protocol"] 364 | }); 365 | 366 | let scripts_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::Scripts as usize]]; 367 | let scripts = json!({ 368 | &scripts_keys[0]: DEVICE["scripts"]["count"], 369 | &scripts_keys[1]: DEVICE["scripts"]["non_script_count"], 370 | &scripts_keys[2]: 0, 371 | &scripts_keys[4]: DEVICE["scripts"]["in_documentElement"], 372 | &scripts_keys[6]: DEVICE["scripts"]["in_head"], 373 | &scripts_keys[8]: DEVICE["scripts"]["in_body"] 374 | }); 375 | //println!("{}", serde_json::to_string_pretty(&scripts).unwrap()); 376 | //println!("{:?}", scripts_keys); 377 | 378 | let executed_functions_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::ExecutedFunctions as usize]]; 379 | let executed_functions = json!({ 380 | &executed_functions_keys[0]: DEVICE["executed_functions"]["func_1"], 381 | &executed_functions_keys[1]: DEVICE["executed_functions"]["func_2"], 382 | &executed_functions_keys[2]: DEVICE["executed_functions"]["func_3"], 383 | &executed_functions_keys[3]: dynamic_func_res, 384 | }); 385 | 386 | let visual_viewport_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::VisualViewport as usize]]; 387 | let visual_viewport = json!({ 388 | &visual_viewport_keys[0]: DEVICE["visual_viewport"]["width"], 389 | &visual_viewport_keys[1]: DEVICE["visual_viewport"]["height"], 390 | &visual_viewport_keys[2]: DEVICE["visual_viewport"]["scale"], 391 | }); 392 | 393 | let html_create_function_names = json!([ 394 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([0,"createAttribute"])), 395 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([1,"createElement"])), 396 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([2,"createElementNS"])), 397 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([3,null])), 398 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([4,null])), 399 | solver.encoders.encode(EncoderIndices::HtmlCreateFunctionNames, json!([5,null])), 400 | ]); 401 | 402 | let div_block = json!([ 403 | [div_property_keys[0],"n","n",true], 404 | [div_property_keys[1],"s","s",true], 405 | [div_property_keys[2],"s","s",true], 406 | [div_property_keys[3],"n","n",true], 407 | [div_property_keys[4],"s","s",true], 408 | [div_property_keys[5],"o","u",false] 409 | ]); 410 | 411 | let created_divs_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::CreatedDivs as usize]]; 412 | let created_divs = json!({ 413 | &created_divs_keys[0]: div_block, 414 | //&created_divs_keys[1]: div_block 415 | }); 416 | //println!("{}", serde_json::to_string_pretty(&created_divs).unwrap()); 417 | 418 | //println!("{:?}", div_property_keys); 419 | //println!("{}", serde_json::to_string_pretty(&created_divs).unwrap()); 420 | // 421 | //return json!({}); 422 | 423 | let typeof_checks_extra_keys: &Vec = &keys_map[&keys_order[ExtrakeyIndices::TypeofChecks as usize]]; 424 | let typeof_checks_arr = DEVICE["typeof_checks"].as_array().unwrap().iter(); 425 | let typeof_checks_values: Vec = typeof_checks_arr.map(|func| { 426 | let obj = json!({ 427 | &typeof_checks_extra_keys[0]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["type_of"].as_str().unwrap()), 428 | &typeof_checks_extra_keys[1]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["stringified_no_name"].as_str().unwrap().len()), 429 | &typeof_checks_extra_keys[2]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["stringified_no_name"].as_str().unwrap().len()), 430 | &typeof_checks_extra_keys[3]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["stringified_no_func"].as_str().unwrap()), 431 | &typeof_checks_extra_keys[4]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["stringified_no_func"].as_str().unwrap()), 432 | &typeof_checks_extra_keys[5]: solver.encoders.encode(EncoderIndices::TypeofChecks, func["func_name"].as_str().unwrap()), 433 | }); 434 | solver.encoders.encode(EncoderIndices::TypeofChecks, obj) 435 | }).collect(); 436 | 437 | let typeof_checks_keys: &Vec = &keys_map[&keys_order[SubkeyIndices::TypeofChecks as usize]]; 438 | let typeof_checks = json!({ 439 | &typeof_checks_keys[0]: typeof_checks_values[0], 440 | &typeof_checks_keys[1]: typeof_checks_values[1], 441 | &typeof_checks_keys[2]: typeof_checks_values[2], 442 | &typeof_checks_keys[3]: typeof_checks_values[3], 443 | &typeof_checks_keys[4]: typeof_checks_values[4], 444 | &typeof_checks_keys[5]: typeof_checks_values[5], 445 | &typeof_checks_keys[6]: typeof_checks_values[6], 446 | &typeof_checks_keys[7]: typeof_checks_values[7], 447 | &typeof_checks_keys[8]: typeof_checks_values[8], 448 | &typeof_checks_keys[9]: typeof_checks_values[9], 449 | &typeof_checks_keys[10]: typeof_checks_values[10] 450 | }); 451 | 452 | //println!("{}", serde_json::to_string_pretty(&typeof_checks).unwrap()); 453 | 454 | let navigator_property_checks: serde_json::Value = navigator_property_keys.iter().map(|key| json!([key, navigator_property_value])).collect(); 455 | //println!("{}", serde_json::to_string_pretty(&navigator_property_checks).unwrap()); 456 | 457 | let main_keys = keys_map[&keys_order[MAIN_KEY_INDEX]].clone(); 458 | 459 | let mut payload = Payload::new(main_keys.clone(), solver.is_waf); 460 | payload.insert_main(MainIndices::Telemetry, telemetry); 461 | payload.insert_main(MainIndices::BasDetection, DEVICE["bas_detection"].clone()); 462 | payload.insert_main(MainIndices::SiteKey, sitekey.as_str()); 463 | payload.insert_main(MainIndices::StaticNum, solver.encoders.encode(EncoderIndices::StaticNum, 1)); 464 | payload.insert_main(MainIndices::ScriptLoadTime, solver.encoders.encode(EncoderIndices::ScriptLoadTime, get_unix_ts())); 465 | payload.insert_main(MainIndices::ScriptInterrogationCounter, solver.encoders.encode(EncoderIndices::ScriptInterrogationCounter, 1)); 466 | payload.insert_main(MainIndices::Slc, solver.encoders.encode(EncoderIndices::Slc, 1)); 467 | payload.insert_main(MainIndices::Gcs, solver.encoders.encode(EncoderIndices::Gcs, serde_json::to_value(["onProtectionInitialized"]).unwrap())); 468 | payload.insert_main(MainIndices::PropertyChecks, DEVICE["property_checks"].clone()); 469 | payload.insert_main(MainIndices::UserAgent, solver.user_agent.as_str()); 470 | payload.insert_main(MainIndices::Language, DEVICE["language"].clone()); 471 | payload.insert_main(MainIndices::Languages, languages); 472 | payload.insert_main(MainIndices::Timings, solver.encoders.encode(EncoderIndices::Timings, timings)); 473 | payload.insert_main(MainIndices::MimeTypes, solver.encoders.encode(EncoderIndices::MimeTypes, mime_types)); 474 | payload.insert_main(MainIndices::Screen, solver.encoders.encode(EncoderIndices::Screen, screen)); 475 | payload.insert_main(MainIndices::TimezoneOffset, DEVICE["timezone_offset"].clone()); 476 | payload.insert_main(MainIndices::IndexedDb, DEVICE["indexed_db"].clone()); 477 | payload.insert_main(MainIndices::AddBehavior, DEVICE["add_behavior"].clone()); 478 | payload.insert_main(MainIndices::OpenDatabase, DEVICE["open_database"].clone()); 479 | payload.insert_main(MainIndices::CpuClass, DEVICE["cpu_class"].clone()); 480 | payload.insert_main(MainIndices::Platform, DEVICE["platform"].clone()); 481 | payload.insert_main(MainIndices::DoNotTrack, DEVICE["do_not_track"].clone()); 482 | payload.insert_main(MainIndices::PluginList, DEVICE["plugins_list"].clone()); 483 | payload.insert_main(MainIndices::PluginFunctions, plugin_functions); 484 | payload.insert_main(MainIndices::Canvas, solver.encoders.encode(EncoderIndices::Canvas, canvas)); 485 | payload.insert_main(MainIndices::Image, image); 486 | payload.insert_main(MainIndices::WebGL, solver.encoders.encode(EncoderIndices::WebGL, web_gl)); 487 | payload.insert_main(MainIndices::SmallImage, small_image); 488 | payload.insert_main(MainIndices::WebGLPrototypes, web_gl_prototypes); 489 | payload.insert_main(MainIndices::TouchData, solver.encoders.encode(EncoderIndices::TouchData, touch_data)); 490 | payload.insert_main(MainIndices::VideoChecks, solver.encoders.encode(EncoderIndices::VideoChecks, video_checks)); 491 | payload.insert_main(MainIndices::AudioChecks, solver.encoders.encode(EncoderIndices::AudioChecks, audio_checks)); 492 | payload.insert_main(MainIndices::Vendor, &DEVICE["vendor"]); 493 | payload.insert_main(MainIndices::Product, &DEVICE["product"]); 494 | payload.insert_main(MainIndices::ProductSub, &DEVICE["productSub"]); 495 | payload.insert_main(MainIndices::ChromeProperties, solver.encoders.encode(EncoderIndices::ChromeProperties, chrome_app_checks)); 496 | payload.insert_main(MainIndices::RandomProperties, solver.encoders.encode(EncoderIndices::RandomProperties, random_properties)); 497 | payload.insert_main(MainIndices::Protocol, protocol); 498 | payload.insert_main(MainIndices::Fonts, &DEVICE["fonts"]); 499 | payload.insert_main(MainIndices::Scripts, scripts); 500 | payload.insert_main(MainIndices::ExecutedFunctions, solver.encoders.encode(EncoderIndices::ExecutedFunctions, executed_functions)); 501 | payload.insert_main(MainIndices::WindowPropertyDescriptors, solver.encoders.encode(EncoderIndices::WindowPropertyDescriptors, DEVICE["window_property_descriptors"].as_str().unwrap())); 502 | payload.insert_main(MainIndices::BrowserOnEvents, solver.encoders.encode(EncoderIndices::BrowserOnEvents, json!([["onbeforeinstallprompt","gsec"],["onbeforexrselect","gsec"],["onbeforeinput","gsec"],["onbeforematch","gsec"],["onbeforetoggle","gsec"],["onblur","gsec"],["onbeforeprint","gsec"],["onbeforeunload","gsec"],["onunhandledrejection","gsec"],["onunload","gsec"]]))); 503 | payload.insert_main(MainIndices::Window30PropertyNames, solver.encoders.encode(EncoderIndices::Window30PropertyNames, json!(["PushSubscrip$","RemotePlayba$","ScrollTimeli$","ViewTimeline","SharedWorker","SpeechSynthe$","SpeechSynthe$","SpeechSynthe$","SpeechSynthe$","SpeechSynthe$","VideoPlaybac$","VisibilitySt$","webkitSpeech$","webkitSpeech$","webkitSpeech$","webkitSpeech$","webkitSpeech$","webkitReques$","webkitResolv$","showBlockPag$","onProtection$","reeseSkipExp$","e","a1_0x1092","a1_0x21cc","reese84","reese84inter$","initializePr$","protectionSu$","protectionLo$"]))); 504 | payload.insert_main(MainIndices::VisualViewport, solver.encoders.encode(EncoderIndices::VisualViewport, visual_viewport)); 505 | payload.insert_main(MainIndices::HtmlCreateFunctionNames, html_create_function_names); 506 | payload.insert_main(MainIndices::HighSurrogate, solver.encoders.encode(EncoderIndices::HighSurrogate, json!([]))); 507 | payload.insert_main(MainIndices::SkipReeseExpiration, true); 508 | 509 | if solver.is_waf { 510 | payload.insert_main(MainIndices::WafAlwaysTrue, true); 511 | } 512 | 513 | payload.insert_main(MainIndices::WorkerIsFunction, true); 514 | payload.insert_main(MainIndices::WebAssemblyIsObject, true); 515 | payload.insert_main(MainIndices::CreatedDivs, solver.encoders.encode(EncoderIndices::CreatedDivs, created_divs)); 516 | payload.insert_main(MainIndices::TypeofChecks, solver.encoders.encode(EncoderIndices::TypeofChecks, typeof_checks)); 517 | payload.insert_main(MainIndices::NavigatorPropertyChecks, solver.encoders.encode(EncoderIndices::NavigatorPropertyChecks, navigator_property_checks)); 518 | payload.insert_main(MainIndices::Checksum, solver.encoders.encode(EncoderIndices::Checksum, checksum)); 519 | payload.insert_main(MainIndices::VersionState, solver.encoders.encode(EncoderIndices::VersionState, DEVICE["version_state"].as_str().unwrap())); 520 | payload.insert_main(MainIndices::VersionNum, solver.encoders.encode(EncoderIndices::VersionNum, (*version_num_str).as_str())); 521 | payload.insert_main(MainIndices::SessionStr, solver.encoders.encode(EncoderIndices::SessionStr, (*session_str).as_str())); 522 | 523 | //println!("{}", serde_json::to_string_pretty(&payload).unwrap()); 524 | //println!("{}", &main_keys[MainIndeces::SessionStr as usize]); 525 | //println!("{}", solver.encoders[EncoderIndices::Checksum as usize]._id); 526 | 527 | #[cfg(debug_assertions)] 528 | if std::env::var("DEBUG").ok() == Some("1".to_string()) { 529 | 530 | let legit_payload: serde_json::Map = serde_json::from_str(std::fs::read_to_string("./debug/legit_payload.json").unwrap().as_str()) 531 | .unwrap(); 532 | let legit_payload_keys = legit_payload.keys().into_iter().collect::>(); 533 | 534 | let genned_payload = payload.clone(); 535 | let genned_payload_keys = genned_payload.keys(); 536 | 537 | for key in legit_payload_keys.iter() { 538 | if genned_payload_keys.contains(&key) {continue} 539 | println!("Key {key} not present in genned payload") 540 | } 541 | 542 | for key in genned_payload_keys.iter() { 543 | if legit_payload_keys.contains(&key) {continue} 544 | println!("Key {key} not present in legit payload") 545 | } 546 | 547 | let mut cnt = 0; 548 | for key in legit_payload_keys { 549 | if !genned_payload_keys.contains(&key) {continue} 550 | 551 | if genned_payload.get(key) != legit_payload.get(key) { 552 | let _index = main_keys.iter().position(|x| x == key).unwrap(); 553 | println!("ineq {:?} {} index {}", MainIndices::index_enum(cnt).unwrap(), key, cnt); 554 | } else { 555 | //println!("equal {}", key) 556 | } 557 | cnt += 1; 558 | 559 | } 560 | 561 | /* 562 | if let serde_json::Value::Object(map) = &legit_payload { 563 | let keys: Vec<&str> = map.keys().map(|s| s.as_str()).collect(); 564 | let mut cnt = 0; 565 | for key in keys { 566 | if payload[key] != legit_payload[key] { 567 | let _index = main_keys.iter().position(|x| x == key).unwrap(); 568 | println!("ineq {:?} {} index {}", MainIndeces::index_enum(cnt).unwrap(), key, cnt); 569 | } else { 570 | //println!("equal {}", key) 571 | } 572 | cnt += 1; 573 | } 574 | //println!("{}", serde_json::to_string_pretty(&payload).unwrap()); 575 | //println!("equal {}", solver.encoders[EncoderIndices::ChromeProperties as usize]._id) 576 | } 577 | */ 578 | println!("Checksum: {}", checksum); 579 | 580 | #[cfg(debug_assertions)] 581 | { 582 | use clipboard::ClipboardProvider; 583 | use clipboard::ClipboardContext; 584 | let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap(); 585 | let text = payload.to_string_pretty(); 586 | ctx.set_contents(text.to_owned()).unwrap(); 587 | } 588 | } 589 | 590 | let sensor = json!({ 591 | "p": solver.encoders.encode(EncoderIndices::Payload, payload.take()), 592 | "st": extracted_data.st, 593 | "sr": extracted_data.sr, 594 | "cr": solver.seed, 595 | "og": 2 596 | }); 597 | 598 | let solution = json!({ 599 | "solution": { 600 | "interrogation": sensor, 601 | "version": DEVICE["version_state"].as_str().unwrap() 602 | }, 603 | "old_token": null, 604 | "error": null, 605 | "performance": { 606 | "interrogation": get_unix_ts() % 200 + 180 607 | } 608 | }); 609 | 610 | (solution, sitekey.to_string()) 611 | } -------------------------------------------------------------------------------- /src/reese.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | #[cfg(not(debug_assertions))] 3 | use rand::Rng; 4 | use serde_json::Value; 5 | use tokio::task::JoinError; 6 | 7 | use crate::encoder::{assemble_encoders, Encoders}; 8 | use crate::payload::gen_sensor; 9 | use crate::extract::Extractor; 10 | //use crate::utils::calc_signature; 11 | //use crate::cache::CACHE; 12 | 13 | #[derive(serde::Serialize, serde::Deserialize)] 14 | pub struct ReeseTaskData { 15 | script: String, 16 | user_agent: String 17 | } 18 | 19 | #[derive(serde::Serialize, serde::Deserialize)] 20 | pub struct ReeseResult { 21 | pub solution: Value, 22 | pub sitekey: String 23 | } 24 | 25 | pub struct ReeseSolver<'a> { 26 | 27 | pub user_agent: String, 28 | 29 | pub seed: u64, 30 | pub dynamic_script: &'a str, 31 | pub static_script: &'a str, 32 | 33 | pub encoders: Encoders<'a>, 34 | pub extractor: Extractor, 35 | 36 | //signature: u64, 37 | pub is_waf: bool 38 | } 39 | 40 | impl<'a> ReeseSolver<'a> { 41 | pub fn new(script: &'a String, user_agent: String) -> Result { 42 | 43 | #[cfg(not(debug_assertions))] 44 | let seed = rand::thread_rng().gen_range(0..1073741824); 45 | 46 | #[cfg(debug_assertions)] 47 | let seed = 0; 48 | 49 | let (dynamic_script, static_script) = if let Some(x) = script.split_once("\n") { 50 | x 51 | } else { 52 | return Err(anyhow!("Malformed script")) 53 | }; 54 | 55 | Ok( 56 | Self { 57 | user_agent, 58 | seed: seed, 59 | dynamic_script, 60 | static_script, 61 | encoders: Encoders::empty(), 62 | extractor: Extractor::new(), 63 | //signature: calc_signature(script), 64 | 65 | is_waf: true 66 | } 67 | ) 68 | } 69 | 70 | pub fn solve(mut self) -> Result { 71 | 72 | /* 73 | 74 | if let Some(cached) = CACHE.get(self.signature).await { 75 | 76 | //self.encoders = cached.encoders; 77 | //self.extractor = cached.extractor; 78 | 79 | // update seed inside encoders after reusing 80 | //self.encoders.iter_mut().for_each(|encoder| encoder.update_session_seed(self.seed)); 81 | 82 | } else { 83 | 84 | // ~80µs 85 | self.encoders = assemble_encoders(&self.dynamic_script, self.seed, self.is_waf); 86 | self.extractor.extract(&self.dynamic_script, &self.static_script); 87 | 88 | } 89 | */ 90 | 91 | self.encoders = assemble_encoders(self.dynamic_script, self.seed, self.is_waf); 92 | self.extractor.extract(self.dynamic_script, self.static_script).unwrap(); 93 | 94 | let (sensor, sitekey) = gen_sensor(&mut self); 95 | //self.store_in_cache().await; 96 | 97 | Ok( 98 | ReeseResult { solution: sensor, sitekey: sitekey } 99 | ) 100 | } 101 | 102 | } 103 | 104 | pub async fn solve_reese_catching(script: String, user_agent: String) -> Result { 105 | 106 | tokio::task::spawn(async move { 107 | let solver = ReeseSolver::new(&script, user_agent).unwrap(); 108 | solver.solve().unwrap() // ~2100µs 109 | }) 110 | .await 111 | 112 | } 113 | 114 | 115 | pub fn solve_reese(script: String, user_agent: String) -> Result { 116 | 117 | let solver = ReeseSolver::new(&script, user_agent).unwrap(); 118 | solver.solve()// ~2100µs 119 | 120 | } -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::{time::{SystemTime, UNIX_EPOCH}, vec}; 2 | use sha1::{Sha1, Digest}; 3 | 4 | use crate::device::DEVICE; 5 | 6 | lazy_static::lazy_static! { 7 | static ref SCREEN_WIDTH: String = DEVICE["screen"]["width"].to_string(); 8 | static ref SCREEN_HEIGHT: String = DEVICE["screen"]["height"].to_string(); 9 | } 10 | 11 | static SHA1_SIZE: usize = 20; 12 | 13 | pub fn get_unix_ts() -> u128 { 14 | let start = SystemTime::now(); 15 | let since_the_epoch = start 16 | .duration_since(UNIX_EPOCH) 17 | .expect("Time went backwards"); 18 | return since_the_epoch.as_millis() 19 | } 20 | 21 | pub fn sha1(input: String) -> Vec { 22 | let mut sha1 = Sha1::new(); 23 | sha1.update(input.as_bytes()); 24 | let bytes: Vec = sha1.finalize().to_vec(); 25 | return bytes; 26 | } 27 | 28 | pub fn solve_dynamic_func(seed: u64, dynamic_string: &str) -> String { 29 | let input: String = format!("{}{}", dynamic_string, seed); 30 | let bytes: Vec = sha1(input); 31 | let static_str: Vec = "y() { [native code] }" 32 | .chars() 33 | .enumerate() 34 | .map(|(i, c)| { 35 | c as u8 ^ bytes[i % SHA1_SIZE] & 127 36 | }) 37 | .collect(); 38 | String::from_utf8(static_str).unwrap() 39 | } 40 | 41 | pub fn calc_checksum(seed: &str, sr: String, user_agent: &str, checksum_arr: &Vec) -> u32 { 42 | //let checksum_arr = extract_checksum_arr(script).unwrap(); 43 | let steps = vec![ 44 | seed, 45 | &sr, 46 | user_agent, 47 | DEVICE["language"].as_str().unwrap(), 48 | SCREEN_WIDTH.as_str(), 49 | SCREEN_HEIGHT.as_str(), 50 | DEVICE["plugins_list"].as_str().unwrap(), 51 | DEVICE["window_property_descriptors"].as_str().unwrap() 52 | ]; 53 | 54 | let mut checksum: i32 = -1; 55 | 56 | for input in steps { 57 | for char in input.as_bytes() { 58 | let index = (checksum ^ *char as i32) & 255; 59 | checksum = ((checksum as u32).wrapping_shr(8) ^ checksum_arr[index as usize] as u32) as i32; 60 | } 61 | } 62 | (checksum as u32 ^ u32::MAX).wrapping_shr(0) 63 | } 64 | 65 | pub fn substr(script: &str, relative_offset: [f64; 2]) -> &str { 66 | let len = script.len() as f64; 67 | let start = (len * relative_offset[0]) as usize; 68 | let end = (len as f64 * relative_offset[1]) as usize; 69 | &script[start..end] 70 | } 71 | 72 | //pub fn calc_signature(script: &str) -> u64 { 73 | // let mut signature = 0_u64; 74 | // for (index, c) in script[10..30].as_bytes().iter().enumerate() { 75 | // signature += *c as u64 * 10_u64.pow((index / 3) as u32) 76 | // } 77 | // signature 78 | //} --------------------------------------------------------------------------------