├── requirements.txt ├── MANIFEST.in ├── img └── smoke.png ├── .gitignore ├── autoit_ripper ├── __init__.py ├── lame.py ├── cli.py ├── mt.py ├── decompress.py ├── utils.py ├── opcodes.py ├── autoit_unpack.py └── autoit_data.py ├── setup.py ├── LICENSE ├── autoit_rule.yar └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | pefile 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | -------------------------------------------------------------------------------- /img/smoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nazywam/AutoIt-Ripper/HEAD/img/smoke.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.pyc 3 | .mypy_cache 4 | .vscode 5 | venv 6 | dist/ 7 | build/ 8 | autoit_ripper.egg-info/ 9 | -------------------------------------------------------------------------------- /autoit_ripper/__init__.py: -------------------------------------------------------------------------------- 1 | from .autoit_unpack import AutoItVersion, extract 2 | 3 | __all__ = ["extract", "AutoItVersion"] 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="autoit-ripper", 8 | version="1.1.2", 9 | author="nazywam", 10 | author_email="nazywam@gmail.com", 11 | description="Extract AutoIt scripts embedded in PE binaries", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/nazywam/AutoIt-Ripper", 15 | packages=setuptools.find_packages(), 16 | install_requires=open("requirements.txt").read().splitlines(), 17 | entry_points={ 18 | "console_scripts": [ 19 | "autoit-ripper = autoit_ripper.cli:main", 20 | ], 21 | }, 22 | classifiers=[ 23 | "Programming Language :: Python :: 3", 24 | "License :: OSI Approved :: MIT License", 25 | "Operating System :: OS Independent", 26 | ], 27 | python_requires=">=3.6", 28 | ) 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Michał Praszmo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /autoit_rule.yar: -------------------------------------------------------------------------------- 1 | rule autoit_v3_26 2 | { 3 | meta: 4 | date = "2020-03-12" 5 | author = "nazywam" 6 | description = "Detects AutoIt v3.26+ files" 7 | reference = "https://github.com/nazywam/AutoIt-Ripper" 8 | strings: 9 | $str1 = "This is a third-party compiled AutoIt script." 10 | $str2 = "AU3!EA06" 11 | $str3 = ">>>AUTOIT NO CMDEXECUTE<<<" wide 12 | $str4 = "AutoIt v3" wide 13 | 14 | $magic = { A3 48 4B BE 98 6C 4A A9 99 4C 53 0A 86 D6 48 7D 41 55 33 21 45 41 30 36 } 15 | condition: 16 | $magic or 4 of them 17 | } 18 | 19 | 20 | rule autoit_v3_00 21 | { 22 | meta: 23 | date = "2020-06-07" 24 | author = "nazywam" 25 | description = "Detects AutoIt v3.00 files" 26 | reference = "https://github.com/nazywam/AutoIt-Ripper" 27 | strings: 28 | $str1 = "AU3_GetPluginDetails" 29 | $str2 = "AU3!EA05" 30 | $str3 = "OnAutoItStart" wide 31 | $str4 = "AutoIt v3" wide 32 | $str5 = "AutoIt script files (*.au3, *.a3x)" wide 33 | 34 | $magic = { A3 48 4B BE 98 6C 4A A9 99 4C 53 0A 86 D6 48 7D 41 55 33 21 45 41 30 35 } 35 | condition: 36 | $magic or 4 of them 37 | } 38 | -------------------------------------------------------------------------------- /autoit_ripper/lame.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from typing import List 3 | 4 | 5 | def rolling_rol(x: int, y: int) -> int: 6 | a = (x) << (y & 31) 7 | b = (x) >> (32 - (y & 31)) 8 | return (a | b) & 0xFFFFFFFF 9 | 10 | 11 | class LAME: 12 | c0: int 13 | c1: int 14 | grp1: List[int] 15 | field_D4: int 16 | 17 | def __init__(self) -> None: 18 | self.c0 = 0 19 | self.c1 = 0 20 | self.grp1 = [0 for _ in range(17)] 21 | self.field_D4 = 0 22 | 23 | def fpusht(self) -> float: 24 | rolled = ( 25 | rolling_rol(self.grp1[self.c0], 9) + rolling_rol(self.grp1[self.c1], 13) 26 | ) & 0xFFFFFFFF 27 | self.grp1[self.c0] = rolled 28 | 29 | if self.c0 == 0: 30 | self.c0 = 16 31 | else: 32 | self.c0 -= 1 33 | 34 | if self.c1 == 0: 35 | self.c1 = 16 36 | else: 37 | self.c1 -= 1 38 | 39 | low = int(rolled << 20) & 0xFFFFFFFF 40 | high = ((rolled >> 12) | 0x3FF00000) & 0xFFFFFFFF 41 | 42 | ret = struct.pack(" None: 46 | for i in range(17): 47 | seed = (1 - seed * 0x53A9B4FB) & 0xFFFFFFFF 48 | self.grp1[i] = seed 49 | 50 | self.c0 = 0 51 | self.c1 = 10 52 | 53 | for _ in range(9): 54 | self.fpusht() 55 | 56 | def get_next(self) -> int: 57 | self.fpusht() 58 | return int(self.fpusht() * 256.0) 59 | 60 | def get_n_next(self, num: int) -> bytearray: 61 | ret = bytearray(num) 62 | for i in range(num): 63 | self.fpusht() 64 | x = int(self.fpusht() * 256.0) 65 | ret[i] = x 66 | return ret 67 | -------------------------------------------------------------------------------- /autoit_ripper/cli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | import sys 4 | from pathlib import Path, PureWindowsPath 5 | 6 | from .autoit_unpack import AutoItVersion, extract 7 | 8 | 9 | def main() -> int: 10 | logging.basicConfig() 11 | log = logging.getLogger() 12 | 13 | parser = argparse.ArgumentParser() 14 | parser.add_argument("file", help="input binary") 15 | parser.add_argument("output_dir", help="output directory") 16 | parser.add_argument("--verbose", "-v", action="store_true") 17 | parser.add_argument( 18 | "--ea", 19 | default="guess", 20 | choices=["EA05", "EA06", "guess"], 21 | help="extract a specific version of AutoIt script (default: %(default)s)", 22 | ) 23 | 24 | args = parser.parse_args() 25 | if args.verbose: 26 | log.setLevel(logging.DEBUG) 27 | else: 28 | log.setLevel(logging.INFO) 29 | 30 | with open(args.file, "rb") as f: 31 | file_data = f.read() 32 | 33 | data = None 34 | if args.ea in ("EA05", "guess"): 35 | data = extract(data=file_data, version=AutoItVersion.EA05) 36 | if not data and args.ea in ("EA06", "guess"): 37 | data = extract(data=file_data, version=AutoItVersion.EA06) 38 | 39 | if data: 40 | output = Path(args.output_dir) 41 | if not output.is_dir(): 42 | log.info("The output directory doesn't exist, creating it") 43 | output.mkdir() 44 | 45 | for filename_w, content in data: 46 | # We need to convert the nasty Windows path into a nice, unix one 47 | filename = PureWindowsPath(filename_w) 48 | log.info(f"Storing result in {(output / filename.name).as_posix()}") 49 | (output / filename.name).write_bytes(content) 50 | return 0 51 | return 1 52 | 53 | 54 | if __name__ == "__main__": 55 | sys.exit(main()) 56 | -------------------------------------------------------------------------------- /autoit_ripper/mt.py: -------------------------------------------------------------------------------- 1 | class MT: 2 | def __init__(self, seed: int) -> None: 3 | self.state = [0] * 624 4 | self.state[0] = seed 5 | self.i = 0 6 | 7 | for i in range(1, 624): 8 | last = self.state[i - 1] 9 | self.state[i] = (i + 0x6C078965 * (last ^ (last >> 30))) & 0xFFFFFFFF 10 | 11 | def twist(self) -> None: 12 | for i in range(227): 13 | new_val = self.state[i + 397] 14 | new_val ^= ( 15 | self.state[i] ^ ((self.state[i + 1] ^ self.state[i]) & 0x7FFFFFFE) 16 | ) >> 1 17 | if self.state[i + 1] & 1 != 0: 18 | new_val ^= 0x9908B0DF 19 | self.state[i] = new_val 20 | 21 | for i in range(396): 22 | new_val = self.state[i] 23 | new_val ^= ( 24 | ( 25 | self.state[i + 227] 26 | ^ ((self.state[i + 228] ^ self.state[i + 227]) & 0x7FFFFFFE) 27 | ) 28 | ) >> 1 29 | if self.state[i + 228] & 1 != 0: 30 | new_val ^= 0x9908B0DF 31 | self.state[227 + i] = new_val 32 | 33 | new_val = self.state[396] 34 | new_val ^= ( 35 | (self.state[623] ^ ((self.state[0] ^ self.state[623]) & 0x7FFFFFFE)) 36 | ) >> 1 37 | if self.state[0] & 1 != 0: 38 | new_val ^= 0x9908B0DF 39 | self.state[623] = new_val 40 | 41 | def get_bytes(self, length: int) -> bytes: 42 | result = [] 43 | for _ in range(length): 44 | if self.i % 624 == 0: 45 | self.twist() 46 | 47 | rnd = self.state[self.i % 624] 48 | rnd = ((((rnd >> 11) ^ rnd) & 0xFF3A58AD) << 7) ^ (rnd >> 11) ^ rnd 49 | rnd = ( 50 | ((rnd & 0xFFFFDF8C) << 15) 51 | ^ rnd 52 | ^ ((((rnd & 0xFFFFDF8C) << 15) ^ rnd) >> 18) 53 | ) >> 1 54 | result.append(rnd & 0xFF) 55 | self.i += 1 56 | return bytes(result) 57 | -------------------------------------------------------------------------------- /autoit_ripper/decompress.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Optional 3 | 4 | from .utils import AutoItVersion, BitStream, ByteStream 5 | 6 | # 10 megabytes 7 | MAX_SCRIPT_SIZE = 10 * 10 ** 6 8 | 9 | 10 | EA05_LITERAL = 0 11 | EA06_LITERAL = 1 12 | 13 | 14 | HDR_3_COMP_MAGIC5 = b"EA05" 15 | HDR_3_COMP_MAGIC6 = b"EA06" 16 | HDR_3_COMP_MAGIC0 = b"JB00" 17 | HDR_3_COMP_MAGIC1 = b"JB01" 18 | 19 | log = logging.getLogger(__name__) 20 | 21 | 22 | def read_match_len(bin_data: BitStream) -> int: 23 | func_vec = ( 24 | # nLen ibit getMore 25 | (3, 2, 0b11), # 3 26 | (6, 3, 0b111), # 7 27 | (13, 5, 0b11111), # 31 28 | (44, 8, 255), 29 | (299, 8, 255), 30 | ) 31 | 32 | length = 0 33 | length_add = 0 34 | 35 | for (length, bits, more) in func_vec: 36 | length_add = bin_data.get_bits(bits) 37 | if length_add != more: 38 | break 39 | else: 40 | while True: 41 | length += more 42 | length_add = bin_data.get_bits(bits) 43 | if length_add != more: 44 | break 45 | 46 | return length + length_add 47 | 48 | 49 | def decompress(stream: ByteStream) -> Optional[bytes]: 50 | version = None 51 | comp_magic = stream.get_bytes(4) 52 | 53 | if comp_magic == HDR_3_COMP_MAGIC5: 54 | log.debug("decompress: found a correct EA05 compressed blob") 55 | version = AutoItVersion.EA05 56 | elif comp_magic == HDR_3_COMP_MAGIC6: 57 | log.debug("decompress: found a correct EA06 compressed blob") 58 | version = AutoItVersion.EA06 59 | elif comp_magic == HDR_3_COMP_MAGIC0: 60 | log.debug("decompress: found a correct JB00 compressed blob") 61 | version = AutoItVersion.JB00 62 | elif comp_magic == HDR_3_COMP_MAGIC1: 63 | log.error( 64 | "decompress: found a correct JB01 compressed blob but it's not yet supported" 65 | ) 66 | return None 67 | else: 68 | log.error("Magic mismatch: %s", comp_magic) 69 | return None 70 | 71 | uncompressed_size = stream.u32be() 72 | if uncompressed_size > MAX_SCRIPT_SIZE: 73 | log.error("Uncompressed script size is larger than allowed") 74 | return None 75 | 76 | literal_symbol = EA06_LITERAL if version == AutoItVersion.EA06 else EA05_LITERAL 77 | bin_data = BitStream(stream.get_bytes(None)) 78 | 79 | out_data = bytearray() 80 | 81 | while len(out_data) < uncompressed_size: 82 | if bin_data.get_bits(1) == literal_symbol: 83 | out_data.append(bin_data.get_bits(8)) 84 | else: 85 | if version in (AutoItVersion.EA05, AutoItVersion.EA06): 86 | offset = bin_data.get_bits(0xF) 87 | match_len = read_match_len(bin_data) 88 | else: 89 | offset = bin_data.get_bits(0xD) + 3 90 | match_len = bin_data.get_bits(0x4) + 3 91 | 92 | fillup = match_len - offset 93 | append_data = out_data[-offset:][:match_len] 94 | 95 | def repeat_cut(data: bytes, length: int) -> bytes: 96 | repeat = length // len(data) + 1 97 | return (data * repeat)[:length] 98 | 99 | if fillup > 0: 100 | if fillup == 1: 101 | append_data.extend(append_data[:1]) 102 | else: 103 | append_data.extend(repeat_cut(append_data, fillup)) 104 | 105 | out_data.extend(append_data) 106 | return bytes(out_data) 107 | -------------------------------------------------------------------------------- /autoit_ripper/utils.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from enum import Enum 3 | from itertools import cycle 4 | from struct import unpack_from 5 | from typing import Optional, Tuple 6 | from zlib import adler32 7 | 8 | from .lame import LAME 9 | from .mt import MT 10 | 11 | 12 | class AutoItVersion(Enum): 13 | EA05 = 0 14 | EA06 = 1 15 | JB00 = 2 16 | JB01 = 3 17 | 18 | 19 | def filetime_to_dt(timestamp: int) -> datetime: 20 | # timestamp it FileTime (number of 100-nanosecond intervals since January 1, 1601) 21 | return datetime(1601, 1, 1) + timedelta(microseconds=timestamp // 10) 22 | 23 | 24 | def bytes_to_bitstring(data: bytes) -> str: 25 | return "".join(bin(x)[2:].zfill(8) for x in data) 26 | 27 | 28 | class BitStream: 29 | def __init__(self, data: bytes) -> None: 30 | self._data = bytes_to_bitstring(data) 31 | self._offset = 0 32 | 33 | def get_bits(self, num: int) -> int: 34 | data = self._data[self._offset: self._offset + num] 35 | self._offset += num 36 | return int(data, 2) 37 | 38 | 39 | class ByteStream: 40 | def __init__(self, data: bytes) -> None: 41 | self._data = data 42 | self._offset = 0 43 | 44 | def skip_bytes(self, num: int) -> None: 45 | self._offset += num 46 | 47 | def get_bytes(self, num: Optional[int]) -> bytes: 48 | if num is None: 49 | num = len(self._data) - self._offset 50 | 51 | data = self._data[self._offset: self._offset + num] 52 | self._offset += num 53 | return data 54 | 55 | def _int(self, len: int, signed: bool) -> int: 56 | return int.from_bytes( 57 | bytes=self.get_bytes(len), byteorder="little", signed=signed 58 | ) 59 | 60 | def _int_be(self, len: int, signed: bool) -> int: 61 | return int.from_bytes(bytes=self.get_bytes(len), byteorder="big", signed=signed) 62 | 63 | def f64(self) -> float: 64 | return unpack_from(" int: 67 | return self._int(1, False) 68 | 69 | def i8(self) -> int: 70 | return self._int(1, True) 71 | 72 | def u16(self) -> int: 73 | return self._int(2, False) 74 | 75 | def i16(self) -> int: 76 | return self._int(2, True) 77 | 78 | def u32(self) -> int: 79 | return self._int(4, False) 80 | 81 | def u32be(self) -> int: 82 | return self._int_be(4, False) 83 | 84 | def i32(self) -> int: 85 | return self._int(4, True) 86 | 87 | def u64(self) -> int: 88 | return self._int(8, False) 89 | 90 | def i64(self) -> int: 91 | return self._int(8, True) 92 | 93 | 94 | def xor(data: bytes, key: bytes) -> bytes: 95 | return bytes(a ^ b for a, b in zip(data, cycle(key))) 96 | 97 | 98 | def decrypt_lame(data: bytes, seed: int) -> bytes: 99 | lame = LAME() 100 | lame.srand(seed) 101 | lame_stream = lame.get_n_next(len(data)) 102 | return xor(data, lame_stream) 103 | 104 | 105 | def decrypt_mt(data: bytes, seed: int) -> bytes: 106 | key = MT(seed).get_bytes(len(data)) 107 | return xor(data, key) 108 | 109 | 110 | def crc_data(data: bytes) -> int: 111 | return adler32(data) 112 | 113 | 114 | class DecryptorBase: 115 | au3_Unicode: Optional[bool] = None 116 | au3_ResType: Optional[int] = None 117 | au3_ResSubType: Optional[Tuple[int, int]] = None 118 | au3_ResName: Optional[Tuple[int, int]] = None 119 | au3_ResSize: Optional[int] = None 120 | au3_ResCrcCompressed: Optional[int] = None 121 | au3_ResContent: Optional[int] = None 122 | 123 | def decrypt(self, data: bytes, key: int) -> bytes: 124 | raise NotImplementedError 125 | 126 | 127 | class EA05Decryptor(DecryptorBase): 128 | au3_Unicode = False 129 | au3_ResType = 0x16FA 130 | au3_ResSubType = (0x29BC, 0xA25E) 131 | au3_ResName = (0x29AC, 0xF25E) 132 | au3_ResSize = 0x45AA 133 | au3_ResCrcCompressed = 0xC3D2 134 | au3_ResContent = 0x22AF 135 | 136 | def decrypt(self, data: bytes, key: int) -> bytes: 137 | return decrypt_mt(data, key) 138 | 139 | 140 | class EA06Decryptor(DecryptorBase): 141 | au3_Unicode = True 142 | au3_ResType = 0x18EE 143 | au3_ResSubType = (0xADBC, 0xB33F) 144 | au3_ResName = (0xF820, 0xF479) 145 | au3_ResSize = 0x87BC 146 | au3_ResCrcCompressed = 0xA685 147 | au3_ResContent = 0x2477 148 | 149 | def decrypt(self, data: bytes, key: int) -> bytes: 150 | return decrypt_lame(data, key) 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoIt-Ripper 2 | 3 | ## What is this 4 | This is a short python script that allows for extraction of "compiled" AutoIt scripts from PE executables. 5 | 6 | ## References 7 | This script is **heavily** based on 3 resources, definitely check them out if you want to dig a bit deeper into AutoIt stuff: 8 | * http://files.planet-dl.org/Cw2k/MyAutToExe/index.html 9 | * [Github mirror I](https://github.com/dzzie/myaut_contrib) 10 | * [Github mirror II](https://github.com/PonyPC/myaut_contrib) 11 | * https://github.com/sujuhu/autoit 12 | * https://github.com/Cisco-Talos/clamav-devel/blob/31824a659dff37ae03e3419395bb68e659c2b165/libclamav/autoit.c 13 | 14 | ## Supported AutoIt versions 15 | 16 | ### Ready: 17 | 18 | * `EA05` AutoIt3.00 19 | * `EA06` AutoIt3.26 20 | 21 | ### Unknown: 22 | 23 | * `JB01` AutoHotKey 24 | * `JB01` AutoIT2 25 | 26 | ## Installation 27 | ```shell 28 | python3 -m pip install autoit-ripper 29 | ``` 30 | 31 | or, if you'd like to install the version from sources: 32 | 33 | ```shell 34 | git clone https://github.com/nazywam/AutoIt-Ripper.git 35 | cd AutoIt-Ripper 36 | pip install . 37 | ``` 38 | 39 | ## Running 40 | 41 | From a python script: 42 | ```python 43 | from autoit_ripper import extract, AutoItVersion 44 | 45 | with open("sample.exe", "rb") as f: 46 | file_content = f.read() 47 | 48 | # EA05 for v3.00+, EA06 for v3.26+ 49 | # Omitting `version` or passing None will try both versions 50 | content_list = extract(data=file_content, version=AutoItVersion.EA06) 51 | ``` 52 | 53 | From the commandline: 54 | ```shell 55 | autoit-ripper sample.exe out_directory 56 | ``` 57 | 58 | Help message: 59 | ```shell 60 | autoit-ripper --help 61 | usage: autoit-ripper [-h] [--verbose] [--ea {EA05,EA06,guess}] file output_dir 62 | 63 | positional arguments: 64 | file input binary 65 | output_dir output directory 66 | 67 | optional arguments: 68 | -h, --help show this help message and exit 69 | --verbose, -v 70 | --ea {EA05,EA06,guess} 71 | extract a specific version of AutoIt script (default: guess) 72 | 73 | ``` 74 | 75 | 76 | ## Format documentation 77 | #### (In progress) 78 | 79 | 80 | ### AU3 header 81 | 82 | | Field | Length | encryption (EA05) | encryption (EA06) | Notes | 83 | |:----------------:|:-------------:|:-----------------:|:-----------------:|:---------------------------:| 84 | | "FILE" | 4 | MT(0x16FA) | LAME(0x18EE) | static string | 85 | | flag | 4 | xor(0x29BC) | xor(0xADBC) | | 86 | | auto_str | flag (* 2) | MT(0xA25E + flag)|LAME(0xB33F + flag)| UTF-8/UTF-16 | 87 | | path_len | 4 | xor(0x29AC) | xor(0xF820) | | 88 | | path | path_len (* 2)|MT(0xF25E + path_len)|LAME(0xF479 + path_len) | Path of the compiled script | 89 | | compressed | 1 | None | None | is the script compressed | 90 | | data_size | 4 | xor(0x45AA) | xor(0x87BC) | compressed data size | 91 | | code_size | 4 | xor(0x45AA) | xor(0x87BC) | uncompressed data size | 92 | | crc | 4 | xor(0xC3D2) | xor(0xA685) | compressed data crc checksum| 93 | | creation date | 4 | None | None | file creation date (high) | 94 | | creation date | 4 | None | None | file creation date (low) | 95 | | last update date | 4 | None | None | last edit date (high) | 96 | | last update date | 4 | None | None | last edit date (low) | 97 | | data | data_size |MT(checksum + 0x22af)|LAME(0x2477) | script data | 98 | 99 | ### Differences between v3.00 and v3.26+ 100 | 101 | | | v3.00 | v3.26 | 102 | |--------------------- |-------------------- |--------------------------------------- | 103 | | Code storage | greped by magic | "SCRIPT" resource (/greped by magic?) | 104 | | String encoding | UTF-8 | UTF-16 | 105 | | Encryption | xor/custom MT19937 | xor/LAME crypt | 106 | | Code encryption key | dynamic | static | 107 | | Compression | yes | yes | 108 | | Code "compilation" | no | yes | 109 | | Magic | EA05 | EA06 | 110 | -------------------------------------------------------------------------------- /autoit_ripper/opcodes.py: -------------------------------------------------------------------------------- 1 | from .autoit_data import FUNCTIONS, KEYWORDS, MACROS 2 | from .utils import ByteStream 3 | 4 | KEYWORDS_INVERT_CASE = {i.upper(): i for i in KEYWORDS} 5 | FUNCTIONS_INVERT_CASE = {i.upper(): i for i in FUNCTIONS} 6 | MACROS_INVERT_CASE = {i.upper(): i for i in MACROS} 7 | 8 | 9 | class TokenStream(ByteStream): 10 | def __init__(self, data: bytes) -> None: 11 | super().__init__(data) 12 | self.indent = 0 13 | self.next_indent = 0 14 | 15 | def get_xored_string(self) -> str: 16 | key = self.u32() 17 | if key > len(self._data): 18 | raise Exception("Read xor string out of bounds") 19 | 20 | ret = bytearray(key * 2) 21 | for i in range(key): 22 | c = self.u16() ^ key 23 | ret[i * 2 + 0] = c & 0xFF 24 | ret[i * 2 + 1] = (c >> 8) & 0xFF 25 | return ret.decode("utf-16") 26 | 27 | def peek_next_opcode(self) -> int: 28 | return self._data[self._offset] 29 | 30 | 31 | def escape_string(string: str) -> str: 32 | # escape double qutoes 33 | string = string.replace('"', '""') 34 | return f'"{string}"' 35 | 36 | 37 | def apply_keyword_indent(stream: TokenStream, keyword: str) -> None: 38 | if keyword in ("While", "Do", "For", "Select", "Switch", "Func", "If"): 39 | stream.next_indent += 1 40 | 41 | if keyword in ("Case", "Else", "ElseIf"): 42 | stream.indent -= 1 43 | 44 | if keyword in ( 45 | "WEnd", 46 | "Until", 47 | "Next", 48 | "EndSelect", 49 | "EndSwitch", 50 | "EndFunc", 51 | "EndIf", 52 | ): 53 | stream.next_indent -= 1 54 | stream.indent -= 1 55 | 56 | if keyword in ("Then",): 57 | if stream.peek_next_opcode() != 0x7F: 58 | stream.next_indent -= 1 59 | 60 | if keyword in ("EndFunc",): 61 | stream.next_indent = 0 62 | 63 | 64 | def read_keyword_id(stream: TokenStream) -> str: 65 | keyword_no = stream.i32() 66 | if keyword_no > len(KEYWORDS): 67 | raise Exception("Token not found") 68 | 69 | keyword = KEYWORDS[keyword_no] 70 | apply_keyword_indent(stream, keyword) 71 | return keyword 72 | 73 | 74 | def read_keyword(stream: TokenStream) -> str: 75 | keyword = KEYWORDS_INVERT_CASE[stream.get_xored_string()] 76 | apply_keyword_indent(stream, keyword) 77 | return keyword 78 | 79 | 80 | def capitalize_function(data: str) -> str: 81 | if data in FUNCTIONS_INVERT_CASE: 82 | return FUNCTIONS_INVERT_CASE[data] 83 | return data 84 | 85 | 86 | def capitalize_macro(data: str) -> str: 87 | if data in MACROS_INVERT_CASE: 88 | return MACROS_INVERT_CASE[data] 89 | return data 90 | 91 | 92 | OPCODES = { 93 | # Keyword 94 | 0x00: read_keyword_id, 95 | # Function 96 | 0x01: lambda x: FUNCTIONS[x.i32()], 97 | # Numbers 98 | 0x05: lambda x: str(x.u32()), 99 | 0x10: lambda x: str(x.u64()), 100 | 0x20: lambda x: str(x.f64()), 101 | # Statements 102 | 0x30: read_keyword, 103 | 0x31: lambda x: capitalize_function(x.get_xored_string()), 104 | 0x32: lambda x: "@" + capitalize_macro(x.get_xored_string()), 105 | 0x33: lambda x: "$" + x.get_xored_string(), 106 | 0x34: lambda x: x.get_xored_string(), 107 | 0x35: lambda x: "." + x.get_xored_string(), 108 | 0x36: lambda x: escape_string(x.get_xored_string()), 109 | 0x37: lambda x: x.get_xored_string(), 110 | # Operators 111 | 0x40: lambda x: ",", 112 | 0x41: lambda x: "=", 113 | 0x42: lambda x: ">", 114 | 0x43: lambda x: "<", 115 | 0x44: lambda x: "<>", 116 | 0x45: lambda x: ">=", 117 | 0x46: lambda x: "<=", 118 | 0x47: lambda x: "(", 119 | 0x48: lambda x: ")", 120 | 0x49: lambda x: "+", 121 | 0x4A: lambda x: "-", 122 | 0x4B: lambda x: "/", 123 | 0x4C: lambda x: "*", 124 | 0x4D: lambda x: "&", 125 | 0x4E: lambda x: "[", 126 | 0x4F: lambda x: "]", 127 | 0x50: lambda x: "==", 128 | 0x51: lambda x: "^", 129 | 0x52: lambda x: "+=", 130 | 0x53: lambda x: "-=", 131 | 0x54: lambda x: "/=", 132 | 0x55: lambda x: "*=", 133 | 0x56: lambda x: "&=", 134 | 0x57: lambda x: "?", 135 | 0x58: lambda x: ":", 136 | } 137 | 138 | 139 | def deassemble_script(script_data: bytes, indent_lines: bool = True) -> str: 140 | stream = TokenStream(script_data) 141 | 142 | lines_no = stream.u32() 143 | current_line = 0 144 | 145 | INDENT_STR = "\t" if indent_lines else "" 146 | 147 | out = [] 148 | line_items = [] 149 | 150 | while current_line < lines_no: 151 | opcode = stream.u8() 152 | if opcode in OPCODES: 153 | line_items.append(OPCODES[opcode](stream)) 154 | 155 | elif opcode == 0x7F: 156 | current_line += 1 157 | final_line = INDENT_STR * stream.indent + " ".join(line_items) + "\r\n" 158 | line_items = [] 159 | stream.indent = stream.next_indent 160 | out.append(final_line) 161 | else: 162 | raise Exception(f"Unsupported opcode: {hex(opcode)}") 163 | 164 | return "".join(out) 165 | -------------------------------------------------------------------------------- /autoit_ripper/autoit_unpack.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Iterator, List, Optional, Tuple, Union 3 | 4 | import pefile # type: ignore 5 | 6 | from .decompress import decompress 7 | from .opcodes import deassemble_script 8 | from .utils import ( 9 | AutoItVersion, 10 | ByteStream, 11 | EA05Decryptor, 12 | EA06Decryptor, 13 | crc_data, 14 | filetime_to_dt, 15 | ) 16 | 17 | log = logging.getLogger(__name__) 18 | 19 | 20 | EA05_MAGIC = bytes.fromhex("a3484bbe986c4aa9994c530a86d6487d41553321") 21 | 22 | 23 | def find_root_dir(pe: pefile.PE, RT_Name: str) -> Optional[pefile.ResourceDirData]: 24 | dir_entries = [ 25 | entry 26 | for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries 27 | if entry.id == pefile.RESOURCE_TYPE[RT_Name] 28 | ] 29 | if len(dir_entries) == 1: 30 | return dir_entries[0].directory 31 | elif len(dir_entries) == 0: 32 | log.error("Couldn't find any appropiate PE resource directory") 33 | return None 34 | else: 35 | log.error("Found multiple PE resource directories, inspect the binary manually") 36 | return None 37 | 38 | 39 | def get_script_resource(pe: pefile.PE) -> Optional[pefile.Structure]: 40 | root_dirs = find_root_dir(pe=pe, RT_Name="RT_RCDATA") 41 | if not root_dirs: 42 | return None 43 | 44 | for entry in root_dirs.entries: 45 | if entry.name and entry.name.string == b"SCRIPT": 46 | return entry.directory.entries[0].data.struct 47 | return None 48 | 49 | 50 | def read_string( 51 | stream: ByteStream, 52 | decryptor: Union[EA05Decryptor, EA06Decryptor], 53 | keys: Tuple[int, int], 54 | ) -> str: 55 | length = stream.u32() ^ keys[0] 56 | enc_key = length + keys[1] 57 | 58 | if decryptor.au3_Unicode: 59 | length <<= 1 60 | encoding = "utf-16" 61 | else: 62 | encoding = "utf-8" 63 | 64 | return decryptor.decrypt(stream.get_bytes(length), enc_key).decode(encoding) 65 | 66 | 67 | def parse_au3_header( 68 | stream: ByteStream, checksum: int, decryptor: Union[EA05Decryptor, EA06Decryptor] 69 | ) -> Iterator[Tuple[str, bytes]]: 70 | 71 | while True: 72 | file_str = decryptor.decrypt(stream.get_bytes(4), decryptor.au3_ResType) 73 | if file_str != b"FILE": 74 | log.debug("FILE magic mismatch") 75 | # Asssume that this is the end of the embedded data 76 | return 77 | yield 78 | 79 | au3_ResSubType = read_string(stream, decryptor, decryptor.au3_ResSubType) 80 | au3_ResName = read_string(stream, decryptor, decryptor.au3_ResName) 81 | log.debug("Found a new autoit string: %s", au3_ResSubType) 82 | log.debug("Found a new path: %s", au3_ResName) 83 | 84 | if au3_ResSubType == ">>>AUTOIT NO CMDEXECUTE<<<": 85 | stream.skip_bytes(num=1) 86 | next_blob = (stream.u32() ^ decryptor.au3_ResSize) + 0x18 87 | stream.skip_bytes(num=next_blob) # uncompressed_size, crc, CreationTime_64 88 | else: 89 | au3_ResIsCompressed = stream.u8() 90 | au3_ResSizeCompressed = stream.u32() ^ decryptor.au3_ResSize 91 | au3_ResSize = stream.u32() ^ decryptor.au3_ResSize 92 | au3_ResCrcCompressed = stream.u32() ^ decryptor.au3_ResCrcCompressed 93 | 94 | CreationTime = (stream.u32() << 32) | stream.u32() 95 | LastWriteTime = (stream.u32() << 32) | stream.u32() 96 | 97 | creation_time_dt = filetime_to_dt(CreationTime) 98 | last_write_time_dt = filetime_to_dt(LastWriteTime) 99 | 100 | log.debug(f"File creation time: {creation_time_dt}") 101 | log.debug(f"File last write time: {last_write_time_dt}") 102 | 103 | dec_data = decryptor.decrypt( 104 | stream.get_bytes(au3_ResSizeCompressed), 105 | checksum + decryptor.au3_ResContent, 106 | ) 107 | if au3_ResCrcCompressed == crc_data(dec_data): 108 | log.debug("CRC data matches") 109 | else: 110 | log.error("CRC data mismatch") 111 | return 112 | yield 113 | 114 | if au3_ResIsCompressed == 1: 115 | dec = decompress(ByteStream(dec_data)) 116 | if not dec: 117 | log.error("Error while trying to decompress data") 118 | return 119 | yield 120 | dec_data = dec 121 | 122 | if au3_ResSubType == ">>>AUTOIT SCRIPT<<<": 123 | yield ("script.au3", deassemble_script(dec_data).encode()) 124 | elif au3_ResSubType == ">AUTOIT UNICODE SCRIPT<": 125 | yield ("script.au3", dec_data.decode("utf-16").encode()) 126 | elif au3_ResSubType == ">AUTOIT SCRIPT<": 127 | yield ("script.au3", dec_data) 128 | else: 129 | yield (au3_ResSubType, dec_data) 130 | 131 | 132 | def parse_all(stream: ByteStream, version: AutoItVersion) -> List[Tuple[str, bytes]]: 133 | checksum = sum(list(stream.get_bytes(16))) 134 | 135 | if version == AutoItVersion.EA05: 136 | return list( 137 | parse_au3_header( 138 | stream=stream, checksum=checksum, decryptor=EA05Decryptor() 139 | ) 140 | ) 141 | elif version == AutoItVersion.EA06: 142 | return list( 143 | parse_au3_header(stream=stream, checksum=0, decryptor=EA06Decryptor()) 144 | ) 145 | else: 146 | raise Exception("Unsupported autoit version %s", version) 147 | 148 | 149 | def unpack_ea05(binary_data: bytes) -> Optional[List[Tuple[str, bytes]]]: 150 | if EA05_MAGIC not in binary_data: 151 | log.error("Couldn't find the location chunk in binary") 152 | return None 153 | 154 | au_off = binary_data.index(EA05_MAGIC) 155 | stream = ByteStream(binary_data[au_off + 20:]) 156 | 157 | magic = stream.get_bytes(4) 158 | if magic == b"EA05": 159 | parsed_data = parse_all(stream, AutoItVersion.EA05) 160 | elif magic == b"EA06": 161 | parsed_data = parse_all(stream, AutoItVersion.EA06) 162 | else: 163 | log.error("EA05 magic mismatch") 164 | return None 165 | 166 | if not parsed_data: 167 | log.error("Couldn't decode the autoit script") 168 | return None 169 | 170 | return parsed_data 171 | 172 | 173 | def unpack_ea06(binary_data: bytes) -> Optional[List[Tuple[str, bytes]]]: 174 | try: 175 | pe = pefile.PE(data=binary_data, fast_load=True) 176 | except pefile.PEFormatError: 177 | pe = None 178 | if not pe: 179 | log.error("Failed to parse the input file") 180 | return None 181 | 182 | pe.parse_data_directories() 183 | if not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE") or not pe.DIRECTORY_ENTRY_RESOURCE: 184 | log.error("The input file has no resources") 185 | return None 186 | 187 | script_resource = get_script_resource(pe) 188 | if script_resource is None: 189 | log.error("Couldn't find the script resource") 190 | return None 191 | 192 | data_rva = script_resource.OffsetToData 193 | data_size = script_resource.Size 194 | script_data = pe.get_memory_mapped_image()[data_rva: data_rva + data_size] 195 | 196 | stream = ByteStream(bytes(script_data)[0x18:]) 197 | parsed_data = parse_all(stream, AutoItVersion.EA06) 198 | if not parsed_data: 199 | log.error("Couldn't decode the autoit script") 200 | return None 201 | return parsed_data 202 | 203 | 204 | def extract( 205 | data: bytes, version: Optional[AutoItVersion] = None 206 | ) -> Optional[List[Tuple[str, bytes]]]: 207 | if version is None: 208 | log.info("AutoIt version not specified, trying both") 209 | return unpack_ea05(data) or unpack_ea06(data) 210 | elif version == AutoItVersion.EA05: 211 | return unpack_ea05(data) 212 | elif version == AutoItVersion.EA06: 213 | return unpack_ea06(data) 214 | else: 215 | raise Exception("Unknown version specified, use AutoItVersion or None") 216 | -------------------------------------------------------------------------------- /autoit_ripper/autoit_data.py: -------------------------------------------------------------------------------- 1 | KEYWORDS = ( 2 | "", 3 | "And", 4 | "Or", 5 | "Not", 6 | "If", 7 | "Then", 8 | "Else", 9 | "ElseIf", 10 | "EndIf", 11 | "While", 12 | "WEnd", 13 | "Do", 14 | "Until", 15 | "For", 16 | "Next", 17 | "To", 18 | "Step", 19 | "In", 20 | "ExitLoop", 21 | "ContinueLoop", 22 | "Select", 23 | "Case", 24 | "EndSelect", 25 | "Switch", 26 | "EndSwitch", 27 | "ContinueCase", 28 | "Dim", 29 | "ReDim", 30 | "Local", 31 | "Global", 32 | "Const", 33 | "Static", 34 | "Func", 35 | "EndFunc", 36 | "Return", 37 | "Exit", 38 | "ByRef", 39 | "With", 40 | "EndWith", 41 | "True", 42 | "False", 43 | "Default", 44 | "Null", 45 | "Volatile", 46 | "Enum", 47 | ) 48 | 49 | FUNCTIONS = ( 50 | "Abs", 51 | "ACos", 52 | "AdlibRegister", 53 | "AdlibUnRegister", 54 | "Asc", 55 | "AscW", 56 | "ASin", 57 | "Assign", 58 | "ATan", 59 | "AutoItSetOption", 60 | "AutoItWinGetTitle", 61 | "AutoItWinSetTitle", 62 | "Beep", 63 | "Binary", 64 | "BinaryLen", 65 | "BinaryMid", 66 | "BinaryToString", 67 | "BitAND", 68 | "BitNOT", 69 | "BitOR", 70 | "BitRotate", 71 | "BitShift", 72 | "BitXOR", 73 | "BlockInput", 74 | "Break", 75 | "Call", 76 | "CDTray", 77 | "Ceiling", 78 | "Chr", 79 | "ChrW", 80 | "ClipGet", 81 | "ClipPut", 82 | "ConsoleRead", 83 | "ConsoleWrite", 84 | "ConsoleWriteError", 85 | "ControlClick", 86 | "ControlCommand", 87 | "ControlDisable", 88 | "ControlEnable", 89 | "ControlFocus", 90 | "ControlGetFocus", 91 | "ControlGetHandle", 92 | "ControlGetPos", 93 | "ControlGetText", 94 | "ControlHide", 95 | "ControlListView", 96 | "ControlMove", 97 | "ControlSend", 98 | "ControlSetText", 99 | "ControlShow", 100 | "ControlTreeView", 101 | "Cos", 102 | "Dec", 103 | "DirCopy", 104 | "DirCreate", 105 | "DirGetSize", 106 | "DirMove", 107 | "DirRemove", 108 | "DllCall", 109 | "DllCallAddress", 110 | "DllCallbackFree", 111 | "DllCallbackGetPtr", 112 | "DllCallbackRegister", 113 | "DllClose", 114 | "DllOpen", 115 | "DllStructCreate", 116 | "DllStructGetData", 117 | "DllStructGetPtr", 118 | "DllStructGetSize", 119 | "DllStructSetData", 120 | "DriveGetDrive", 121 | "DriveGetFileSystem", 122 | "DriveGetLabel", 123 | "DriveGetSerial", 124 | "DriveGetType", 125 | "DriveMapAdd", 126 | "DriveMapDel", 127 | "DriveMapGet", 128 | "DriveSetLabel", 129 | "DriveSpaceFree", 130 | "DriveSpaceTotal", 131 | "DriveStatus", 132 | "DUMMYSPEEDTEST", 133 | "EnvGet", 134 | "EnvSet", 135 | "EnvUpdate", 136 | "Eval", 137 | "Execute", 138 | "Exp", 139 | "FileChangeDir", 140 | "FileClose", 141 | "FileCopy", 142 | "FileCreateNTFSLink", 143 | "FileCreateShortcut", 144 | "FileDelete", 145 | "FileExists", 146 | "FileFindFirstFile", 147 | "FileFindNextFile", 148 | "FileFlush", 149 | "FileGetAttrib", 150 | "FileGetEncoding", 151 | "FileGetLongName", 152 | "FileGetPos", 153 | "FileGetShortcut", 154 | "FileGetShortName", 155 | "FileGetSize", 156 | "FileGetTime", 157 | "FileGetVersion", 158 | "FileInstall", 159 | "FileMove", 160 | "FileOpen", 161 | "FileOpenDialog", 162 | "FileRead", 163 | "FileReadLine", 164 | "FileReadToArray", 165 | "FileRecycle", 166 | "FileRecycleEmpty", 167 | "FileSaveDialog", 168 | "FileSelectFolder", 169 | "FileSetAttrib", 170 | "FileSetEnd", 171 | "FileSetPos", 172 | "FileSetTime", 173 | "FileWrite", 174 | "FileWriteLine", 175 | "Floor", 176 | "FtpSetProxy", 177 | "FuncName", 178 | "GUICreate", 179 | "GUICtrlCreateAvi", 180 | "GUICtrlCreateButton", 181 | "GUICtrlCreateCheckbox", 182 | "GUICtrlCreateCombo", 183 | "GUICtrlCreateContextMenu", 184 | "GUICtrlCreateDate", 185 | "GUICtrlCreateDummy", 186 | "GUICtrlCreateEdit", 187 | "GUICtrlCreateGraphic", 188 | "GUICtrlCreateGroup", 189 | "GUICtrlCreateIcon", 190 | "GUICtrlCreateInput", 191 | "GUICtrlCreateLabel", 192 | "GUICtrlCreateList", 193 | "GUICtrlCreateListView", 194 | "GUICtrlCreateListViewItem", 195 | "GUICtrlCreateMenu", 196 | "GUICtrlCreateMenuItem", 197 | "GUICtrlCreateMonthCal", 198 | "GUICtrlCreateObj", 199 | "GUICtrlCreatePic", 200 | "GUICtrlCreateProgress", 201 | "GUICtrlCreateRadio", 202 | "GUICtrlCreateSlider", 203 | "GUICtrlCreateTab", 204 | "GUICtrlCreateTabItem", 205 | "GUICtrlCreateTreeView", 206 | "GUICtrlCreateTreeViewItem", 207 | "GUICtrlCreateUpdown", 208 | "GUICtrlDelete", 209 | "GUICtrlGetHandle", 210 | "GUICtrlGetState", 211 | "GUICtrlRead", 212 | "GUICtrlRecvMsg", 213 | "GUICtrlRegisterListViewSort", 214 | "GUICtrlSendMsg", 215 | "GUICtrlSendToDummy", 216 | "GUICtrlSetBkColor", 217 | "GUICtrlSetColor", 218 | "GUICtrlSetCursor", 219 | "GUICtrlSetData", 220 | "GUICtrlSetDefBkColor", 221 | "GUICtrlSetDefColor", 222 | "GUICtrlSetFont", 223 | "GUICtrlSetGraphic", 224 | "GUICtrlSetImage", 225 | "GUICtrlSetLimit", 226 | "GUICtrlSetOnEvent", 227 | "GUICtrlSetPos", 228 | "GUICtrlSetResizing", 229 | "GUICtrlSetState", 230 | "GUICtrlSetStyle", 231 | "GUICtrlSetTip", 232 | "GUIDelete", 233 | "GUIGetCursorInfo", 234 | "GUIGetMsg", 235 | "GUIGetStyle", 236 | "GUIRegisterMsg", 237 | "GUISetAccelerators", 238 | "GUISetBkColor", 239 | "GUISetCoord", 240 | "GUISetCursor", 241 | "GUISetFont", 242 | "GUISetHelp", 243 | "GUISetIcon", 244 | "GUISetOnEvent", 245 | "GUISetState", 246 | "GUISetStyle", 247 | "GUIStartGroup", 248 | "GUISwitch", 249 | "Hex", 250 | "HotKeySet", 251 | "HttpSetProxy", 252 | "HttpSetUserAgent", 253 | "HWnd", 254 | "InetClose", 255 | "InetGet", 256 | "InetGetInfo", 257 | "InetGetSize", 258 | "InetRead", 259 | "IniDelete", 260 | "IniRead", 261 | "IniReadSection", 262 | "IniReadSectionNames", 263 | "IniRenameSection", 264 | "IniWrite", 265 | "IniWriteSection", 266 | "InputBox", 267 | "Int", 268 | "IsAdmin", 269 | "IsArray", 270 | "IsBinary", 271 | "IsBool", 272 | "IsDeclared", 273 | "IsDllStruct", 274 | "IsFloat", 275 | "IsFunc", 276 | "IsHWnd", 277 | "IsInt", 278 | "IsKeyword", 279 | "IsMap", 280 | "IsNumber", 281 | "IsObj", 282 | "IsPtr", 283 | "IsString", 284 | "Log", 285 | "MapAppend", 286 | "MapExists", 287 | "MapKeys", 288 | "MapRemove", 289 | "MemGetStats", 290 | "Mod", 291 | "MouseClick", 292 | "MouseClickDrag", 293 | "MouseDown", 294 | "MouseGetCursor", 295 | "MouseGetPos", 296 | "MouseMove", 297 | "MouseUp", 298 | "MouseWheel", 299 | "MsgBox", 300 | "Number", 301 | "ObjCreate", 302 | "ObjCreateInterface", 303 | "ObjEvent", 304 | "ObjGet", 305 | "ObjName", 306 | "OnAutoItExitRegister", 307 | "OnAutoItExitUnRegister", 308 | "Opt", 309 | "Ping", 310 | "PixelChecksum", 311 | "PixelGetColor", 312 | "PixelSearch", 313 | "ProcessClose", 314 | "ProcessExists", 315 | "ProcessGetStats", 316 | "ProcessList", 317 | "ProcessSetPriority", 318 | "ProcessWait", 319 | "ProcessWaitClose", 320 | "ProgressOff", 321 | "ProgressOn", 322 | "ProgressSet", 323 | "Ptr", 324 | "Random", 325 | "RegDelete", 326 | "RegEnumKey", 327 | "RegEnumVal", 328 | "RegRead", 329 | "RegWrite", 330 | "Round", 331 | "Run", 332 | "RunAs", 333 | "RunAsWait", 334 | "RunWait", 335 | "Send", 336 | "SendKeepActive", 337 | "SetError", 338 | "SetExtended", 339 | "ShellExecute", 340 | "ShellExecuteWait", 341 | "Shutdown", 342 | "Sin", 343 | "Sleep", 344 | "SoundPlay", 345 | "SoundSetWaveVolume", 346 | "SplashImageOn", 347 | "SplashOff", 348 | "SplashTextOn", 349 | "Sqrt", 350 | "SRandom", 351 | "StatusbarGetText", 352 | "StderrRead", 353 | "StdinWrite", 354 | "StdioClose", 355 | "StdoutRead", 356 | "String", 357 | "StringAddCR", 358 | "StringCompare", 359 | "StringFormat", 360 | "StringFromASCIIArray", 361 | "StringInStr", 362 | "StringIsAlNum", 363 | "StringIsAlpha", 364 | "StringIsASCII", 365 | "StringIsDigit", 366 | "StringIsFloat", 367 | "StringIsInt", 368 | "StringIsLower", 369 | "StringIsSpace", 370 | "StringIsUpper", 371 | "StringIsXDigit", 372 | "StringLeft", 373 | "StringLen", 374 | "StringLower", 375 | "StringMid", 376 | "StringRegExp", 377 | "StringRegExpReplace", 378 | "StringReplace", 379 | "StringReverse", 380 | "StringRight", 381 | "StringSplit", 382 | "StringStripCR", 383 | "StringStripWS", 384 | "StringToASCIIArray", 385 | "StringToBinary", 386 | "StringTrimLeft", 387 | "StringTrimRight", 388 | "StringUpper", 389 | "Tan", 390 | "TCPAccept", 391 | "TCPCloseSocket", 392 | "TCPConnect", 393 | "TCPListen", 394 | "TCPNameToIP", 395 | "TCPRecv", 396 | "TCPSend", 397 | "TCPShutdown", 398 | "TCPStartup", 399 | "TimerDiff", 400 | "TimerInit", 401 | "ToolTip", 402 | "TrayCreateItem", 403 | "TrayCreateMenu", 404 | "TrayGetMsg", 405 | "TrayItemDelete", 406 | "TrayItemGetHandle", 407 | "TrayItemGetState", 408 | "TrayItemGetText", 409 | "TrayItemSetOnEvent", 410 | "TrayItemSetState", 411 | "TrayItemSetText", 412 | "TraySetClick", 413 | "TraySetIcon", 414 | "TraySetOnEvent", 415 | "TraySetPauseIcon", 416 | "TraySetState", 417 | "TraySetToolTip", 418 | "TrayTip", 419 | "UBound", 420 | "UDPBind", 421 | "UDPCloseSocket", 422 | "UDPOpen", 423 | "UDPRecv", 424 | "UDPSend", 425 | "UDPShutdown", 426 | "UDPStartup", 427 | "VarGetType", 428 | "WinActivate", 429 | "WinActive", 430 | "WinClose", 431 | "WinExists", 432 | "WinFlash", 433 | "WinGetCaretPos", 434 | "WinGetClassList", 435 | "WinGetClientSize", 436 | "WinGetHandle", 437 | "WinGetPos", 438 | "WinGetProcess", 439 | "WinGetState", 440 | "WinGetText", 441 | "WinGetTitle", 442 | "WinKill", 443 | "WinList", 444 | "WinMenuSelectItem", 445 | "WinMinimizeAll", 446 | "WinMinimizeAllUndo", 447 | "WinMove", 448 | "WinSetOnTop", 449 | "WinSetState", 450 | "WinSetTitle", 451 | "WinSetTrans", 452 | "WinWait", 453 | "WinWaitActive", 454 | "WinWaitClose", 455 | "WinWaitNotActive", 456 | ) 457 | 458 | MACROS = ( 459 | "extended", 460 | "MSEC", 461 | "SEC", 462 | "MIN", 463 | "error", 464 | "HOUR", 465 | "MDAY", 466 | "MON", 467 | "YEAR", 468 | "WDAY", 469 | "YDAY", 470 | "ProgramFilesDir", 471 | "CommonFilesDir", 472 | "MyDocumentsDir", 473 | "AppDataCommonDir", 474 | "DesktopCommonDir", 475 | "DocumentsCommonDir", 476 | "FavoritesCommonDir", 477 | "ProgramsCommonDir", 478 | "StartMenuCommonDir", 479 | "StartupCommonDir", 480 | "LocalAppDataDir", 481 | "AppDataDir", 482 | "DesktopDir", 483 | "FavoritesDir", 484 | "ProgramsDir", 485 | "StartMenuDir", 486 | "StartupDir", 487 | "ComputerName", 488 | "WindowsDir", 489 | "SystemDir", 490 | "SW_HIDE", 491 | "SW_MINIMIZE", 492 | "SW_MAXIMIZE", 493 | "SW_RESTORE", 494 | "SW_SHOW", 495 | "SW_SHOWDEFAULT", 496 | "SW_ENABLE", 497 | "SW_DISABLE", 498 | "SW_SHOWMAXIMIZED", 499 | "SW_SHOWMINIMIZED", 500 | "SW_SHOWMINNOACTIVE", 501 | "SW_SHOWNA", 502 | "SW_SHOWNOACTIVATE", 503 | "SW_SHOWNORMAL", 504 | "SW_LOCK", 505 | "SW_UNLOCK", 506 | "TrayIconVisible", 507 | "TrayIconFlashing", 508 | "ScriptFullPath", 509 | "ScriptName", 510 | "ScriptDir", 511 | "ScriptLineNumber", 512 | "WorkingDir", 513 | "OSType", 514 | "OSVersion", 515 | "OSBuild", 516 | "OSServicePack", 517 | "OSLang", 518 | "ProcessorArch", 519 | "OSArch", 520 | "CPUArch", 521 | "KBLayout", 522 | "AutoItVersion", 523 | "AutoItExe", 524 | "IPAddress1", 525 | "IPAddress2", 526 | "IPAddress3", 527 | "IPAddress4", 528 | "CR", 529 | "LF", 530 | "CRLF", 531 | "DesktopWidth", 532 | "DesktopHeight", 533 | "DesktopDepth", 534 | "DesktopRefresh", 535 | "Compiled", 536 | "ComSpec", 537 | "TAB", 538 | "UserName", 539 | "TempDir", 540 | "UserProfileDir", 541 | "HomeDrive", 542 | "HomePath", 543 | "HomeShare", 544 | "LogonServer", 545 | "LogonDomain", 546 | "LogonDNSDomain", 547 | "InetGetBytesRead ", 548 | "InetGetActive ", 549 | "NumParams", 550 | "HotKeyPressed", 551 | "AutoItPID", 552 | "AutoItUnicode", 553 | "AutoItX64", 554 | "Unicode ", 555 | "MUILang", 556 | "COM_EventObj", 557 | "GUI_CtrlId", 558 | "GUI_CtrlHandle", 559 | "GUI_DragId", 560 | "GUI_DragFile", 561 | "GUI_DropId", 562 | "GUI_WinHandle", 563 | ) 564 | --------------------------------------------------------------------------------