Skip to content

PamStealer comes to Intel Macs: Analyzing the x86_64 build of a Rust macOS stealer

Cristian Molina Cristian Molina
PamStealer comes to Intel Macs: Analyzing the x86_64 build of a Rust macOS stealer

In late August 2026, automated telemetry identified an in-the-wild sample of PamStealer , an emerging Rust-based macOS information stealer first documented by Jamf Threat Labs . Prior public analysis observed PamStealer operating exclusively as an Apple Silicon (arm64) payload delivered via trojanized disk images impersonating the Maccy clipboard utility. This analyzed artifact is the Intel (x86_64) architecture slice of a multi-architecture fat binary, confirming that the threat actors have expanded their build pipeline to ensure uniform execution across legacy and modern Apple hardware.

PamStealer distinguishes itself from typical macOS commodity stealers through a disciplined verification loop and aggressive anti-analysis posture. Rather than exfiltrating raw user input from phishing dialogs, the malware loads libpam.2.dylib at runtime and validates submitted passwords against the operating system's local authentication stack via pam_authenticate, guaranteeing that operators receive only authenticated credentials. The sample establishes redundant persistence across macOS generations by combining the modern SMAppService API with an embedded, decrypted helper invoking legacy LSSharedFileList functions. Harvested targets include Chromium and Gecko browser vaults, messaging databases, and cryptocurrency transactions intercepted via real-time clipboard address replacement across major blockchain assets.

The payload enforces rigorous environmental keying, deriving its XChaCha20-Poly1305 decryption keys through an arithmetic seed contributed by eight static host checks. Execution terminates outright if debugger artifacts, virtualization indicators, or geographic configurations matching Russian and Commonwealth of Independent States (CIS) timezones and language locales are identified. Command and control channels employ decentralized dead-drop resolution via Ethereum smart contract JSON-RPC calls (EtherHiding) alongside HTTPS transport, while an in-memory native module loader permits arbitrary post-exploitation tasking without spawning child processes. We attribute the operation to a financially motivated cybercriminal syndicate operating within the Russian/CIS nexus with moderate confidence.

Attribution and confidence

We attribute the development and operation of this PamStealer build to a financially motivated cybercriminal syndicate operating within the Russian/Commonwealth of Independent States (CIS) nexus, with moderate confidence. This assessment rests primarily on the sample's explicit locale and timezone geofencing logic within resolver_corefoundation_locale_geofence, which terminates execution across Russian and Central Asian administrative regions (including Novosibirsk, Tomsk, Yakutsk, Bishkek, Dushanbe, Tashkent, Samarkand, and Ashgabat) and denies execution across Belarusian, Armenian, Kyrgyz, Azerbaijani, Uzbek, and Turkmen language environments.

Such systematic avoidance of regional infrastructure is a consistent operational trademark of Russian-speaking cybercrime operators seeking to avoid domestic legal jurisdiction. The malware's functional priorities—illicit credential harvesting, browser vault access, and automated cryptocurrency pasteboard substitution across major coin formats—further substantiate a profit-driven intrusion profile rather than state-sponsored cyber espionage.

However, confidence in attributing the sample to a specific named operator cluster remains low: internal image artifacts, including the signing identifier (macos-stealer-v2-...) and campaign parameter (i2), denote a centralized, evolving builder pipeline that can be shared across multiple affiliates, leaving the specific operator of this fat-binary slice unconfirmed without external delivery and telemetry attribution.

What we established

  • The configuration decrypts with a key seed that is a value compiled into the binary, XORed with a constant contributed by each of eight anti-analysis checks. The author most likely built the key this way to stop an analyst reading the configuration out of the file, since tampering with a check changes the seed. It did not hold here. The eight constants are static. We recomputed the seed without running the sample.
  • The configuration cipher is XChaCha20-Poly1305. RFC 8439 defines ChaCha20-Poly1305 with a 12-byte nonce. This one is 24 bytes, which makes it the extended variant and puts an HChaCha20 subkey step in front of the ChaCha core.
  • The password dialog validates against the real authentication stack before the password leaves the machine. Three PAM symbol names are XOR-encoded in the binary and we reproduced each decode loop to the same bytes.
  • The sample establishes persistance twice. It registers a login item through SMAppService, and it decrypts a 15,744-byte helper carried inside itself, writes it to disk and spawns it. That helper imports LSSharedFileListInsertItemURL and installs a second login item through the older API, likely for entrenchment.
  • The primary C2 address is stored in the binary as an encrypted blob. It decrypts under the derived seed, and its Poly1305 tag verifies.

What we found

Defense evasion

resolver_corefoundation_locale_geofence checks the host's region before the collection runs. The timezone denylist covers Novosibirsk, Tomsk, Yakutsk, Ust-Nera, Bishkek, Dushanbe, Tashkent, Samarkand, Ashgabat, Aqtau, Simferopol and Tiraspol, which spans Russia and the Central Asian republics. The language list covers Belarusian, Armenian, Kyrgyz, Azerbaijani, Uzbek and Turkmen. These are also known as CIS countries. Operators commonly add region checks like this to avoid infecting hosts in their own jurisdiction.

Eight of the checks in this suite also fold a constant into the configuration key, which the next section covers. Alongside them, nanosleep calls are backed by ud2 instructions that raise EXC_BAD_INSTRUCTION when a debugger steps over, and file_unlink_selfdelete removes the sample from disk to complete its anti-analysis routine.

Environmental keying

A single 64-bit global holds the key seed. It starts at a value compiled into __data, and eight anti-analysis routines each fold one constant into it. Each fold happens when that routine finds a clean host: System Integrity Protection fully enabled, read through csr_get_active_config; the P_TRACED flag clear on a sysctl query; no callback from _dyld_debugger_notification; and no VMware, VirtualBox, Parallels or VirtIO device names in the IORegistry.

pamstealer 1

Figure 1. The accumulator at its compiled-in value, and the nine references to it: eight anti-analysis routines folding their constant with ^=, and the single reader that returns the result.

One function reads the accumulator. env_keyed_seed_provider returns it only after antidebug_sysctl_ptraced reports a clean process twice. The seed then runs through config_key_derive_hkdf and hmac_sha256_hkdf_mix to produce the AEAD key, and config_xchacha20poly1305_decrypt does the decryption, checking that the nonce is 24 bytes and returning -1 if the Poly1305 tag does not verify.

pamstealer 2

Figure 2. The configuration decryptor. Its first act is an anti-debug check, and a non-zero result returns -1 before decryption begins.

pamstealer 3

Figure 3. The five callers of that decryptor, reaching the C2 record, the campaign tag, the payout address and the 32-byte key.

The eight constants and the starting value are static, so the seed can be computed from the file without running the sample. Computing it opened the four configuration blobs stored in read-only data, each authenticating under its own Poly1305 tag. The C2 address, the campaign tag, an Ethereum payout address and a 32-byte key came out of those four blobs. We searched the image for the C2 address in plaintext and did not find it.

Credential access

pam_password_capture_prompt builds an NSAlert carrying an NSSecureTextField, raises it above other windows with setLevel:, and re-presents it through the run loop until the password it receives validates. Lure text is localized: Norwegian, Danish, English, Swedish, French, Italian and Indonesian variants are held in localized_lure_strings.

Validation runs against the operating system's own authentication stack. The routine calls dlopen on a path built on the stack, which is 23 bytes long and feeds three dlsym calls that resolve PAM symbols, so the library is /usr/lib/libpam.2.dylib. The three symbols resolve, and the sample calls them in order: pam_start(service, user, &conv, &pamh) with its return compared against zero, pam_authenticate(pamh, flags), and pam_end(pamh, status), followed by dlclose.

pamstealer 4

Figure 4. The password prompt's string-decode loop: a rotate-left key schedule with a per-iteration constant, rebuilding a nine-byte symbol name one byte at a time.

The symbol names are not in the binary as text. Each is XOR-encoded with its own key schedule and rebuilt at runtime, a pattern consistent with the obfstr crate. We reproduced the pam_start decode loop in Python, running its ciphertext through the same rotate-and-add schedule, and it prints pam_start. pam_authenticate and pam_end each use a different seed and schedule.

A password that fails pam_authenticate gets the dialog again. One that passes is written to the user_pass field of the exfil beacon and leaves with the rest of the collection. The operator receives passwords that work.

Collection targets

Some of what the sample steals sits behind macOS privacy controls, and code cannot grant itself Full Disk Access. fda_open_privacy_allfiles opens the Full Disk Access pane through a URLWithString: call. That is as far as a process can go. The toggle has to be set by the person at the keyboard. fda_lure_finder_icon is the part that works on them, raising a dialog that loads the genuine Finder.icns and states that Finder lost access to protected data, with an Open Settings button. Whether the grant happened goes back to the operator in the fda_status beacon field.

Browsers

browser_credential_stealer names two families. It looks up Chromium-family secrets by their keychain service names, with strings including Chrome Safe Storage, Chromium Safe Storage and Microsoft Edge Safe Storage, covering Chrome, Chromium, Edge, Brave, Opera and Opera GX, Vivaldi, Thorium and Arc. It reaches Gecko-family browsers through profile paths for Firefox, LibreWolf, Waterfox, Zen and Floorp, and it enumerates Firefox add-ons through extensions.webextensions.uuids. Cookie and login database names appear alongside.

Keychain

The Safe Storage strings are service-name lookups. This build loads no Security.framework and calls no SecItem or SecKeychain function, which we confirmed against the enumerated dlopen and dlsym sites. Whatever unlocks those entries does not come from the keychain API in this binary.

Messaging

A WhatsApp query reads ZWAMESSAGE joined against ZWACHATSESSION, and the iMessage database path appears alongside it.

Clipboard

clipper_clipboard_monitor polls NSPasteboard through changeCount.

Host details

IOPlatformSerialNumber comes out of IOPlatformExpertDevice, the processor name from machdep.cpu.brand_string, core count from hw.logicalcpu, and screen size from CGDisplayPixelsWide. NSRunningApplication and runningApplicationsWithBundleIdentifier: enumerate what is running, and enumerate_and_terminate_apps can terminate a process it finds.

Files

collection_worker reads the targeted files and stages copies, creating directories and setting execute permissions as it goes.

Part of that collection runs whatever the victim does. Chromium and Gecko profile directories sit under ~/Library/Application Support, which a user-level process reads with no privacy prompt. The browser credential theft proceeds without the grant. The iMessage database under ~/Library/Messages, WhatsApp's group container, and the Desktop, Documents and Downloads folders are protected, and reaching those needs the victim to set the toggle. Keychain entries need the login password instead, which the dialog collects. Reporting the outcome in fda_status most likely lets the operator sort hosts by how much of the collection landed.

Persistence

persistence_smappservice registers a login item through ServiceManagement, then drops a second executable that registers another one.

For the first, the routine resolves SMAppService with objc_getClass and sends it two messages whose selectors are XOR-encoded. The 14-byte selector decodes to mainAppService, the 23-byte selector to registerAndReturnError:, composing [[SMAppService mainAppService] registerAndReturnError:&err].

pamstealer 5

Figure 5. The persistence routine staging the embedded helper: a 15,744-byte ChaCha20 blob decrypted in place before it is written and spawned.

The second executable travels inside the binary. persistence_smappservice hands a 15,744-byte blob and a ChaCha20 key and nonce to a decrypt routine. Inside this file the helper is ciphertext until that routine runs. The plaintext is a standalone x86_64 Mach-O whose undefined-symbol table imports LSSharedFileListCreate, LSSharedFileListInsertItemURL, LSSharedFileListCopySnapshot and kLSSharedFileListSessionLoginItems. The sample writes it out and starts it through a posix_spawnp wrapper.

The dropped helper is most likely a fallback for older releases. SMAppService arrived in macOS 13, while LSSharedFileList has been deprecated since macOS 10.11 and the login-items list on current macOS is managed through Background Task Management. A recent Mac keeps the SMAppService registration across a reboot. An older one keeps the helper. We did not test whether LSSharedFileListInsertItemURL still registers an item on macOS 13 or later.

A login item runs as the account that registered it, so the code starts at user login without an administrator prompt. The helper runs as its own process with its own entry under kLSSharedFileListSessionLoginItems. We searched the image for a LaunchAgent plist path and found none, so a hunt across ~/Library/LaunchAgents comes back empty on an infected host.

Command and control

collect_and_exfil_c2 builds a JSON-RPC eth_call carrying the ERC-20 name() selector, and sends it to four public nodes: publicnode, llamarpc, 1rpc and drpc. The response is parsed into a structure at offsets +0x30 and +0x38, and those bytes are handed to the same XChaCha20-Poly1305 decryptor the configuration uses.

An ERC-20 name() call returns a token's human-readable name, and this one is decrypted as an AEAD blob. The contract field is very likely carrying an encrypted configuration, which is the technique commonly called EtherHiding: the operator writes the value into contract storage and the malware reads it back with a free call to a public node.

Ingress tool transfer

backdoor_module_dispatch reads a task envelope carrying server_path, entry_point, args, .module_name, delete_file, delete_after, output_cap and max_module_size. It fetches the named module, writes it, then loads it in process: dlopen, a symbol lookup for entry_point, the call, and dlclose. A failed load takes the branch that reports not loaded. Output comes back bounded by output_cap and acknowledged through completed, checksum: and sha256.

The envelope's fields states its capability and enters through threat-actor-controlled infrastructure, where it passes arguments. The loader then runs the code inside the running process and upon finishing returns a value to the server. The operator therefore runs native code of their choosing on each host, using the compiled-in stealer to deliver it. Process-creation telemetry records no module launch, because the load creates no child process.

Exfiltration

exfil_beacon_json_builder assembles the record that goes out. Its fields are task_id, timestamp, transfer_id, hostname, os_version, browser_type, languages, screen_width, screen_height, cpu_cores, agent_version, fda_status, key_report and user_pass.

exfil_http_helper encrypts that record, base64-encodes the ciphertext and wraps it in a {"data":"..."} envelope whose opening nine bytes are themselves XOR-decoded inline with seed 0x53c6590f. It tail-calls http_post_request_builder, which builds an NSURLSession request with requestWithURL:, sets the method to POST and the content type to application/json, and sends it with dataTaskWithRequest:completionHandler:. The import table lists no networking symbols, because CFNetwork is loaded at runtime from /System/Library/Frameworks/CFNetwork.framework.

Collected files travel separately. exfil_upload_transport_targz packs them into a tar.gz and uploads it in chunks, opening with an upload_init handshake, sending each chunk, and closing on a completed acknowledgement, with c2_module_send_protocol carrying the wire format and init_rejected( marking a refused handshake.

he envelope finally moves credentials off a monitored network without showing what the request carries. A proxy that terminates TLS sees a POST of application/json to an HTTPS host with a single data field, which is the shape of ordinary application telemetry, and the record inside is encrypted under the same XChaCha20-Poly1305 scheme as the configuration.

Financial theft

clipper_clipboard_monitor polls NSPasteboard through changeCount. Each new value goes to clipper_wallet_replace, which tests it against one regular expression per currency. The set covers Bitcoin, Bitcoin Cash, Litecoin, Monero, Dogecoin, Tron, and Zcash in its sapling and unified forms.

Upon matching, the routine writes the operator's address to the pasteboard in place of the one that was copied. The Bitcoin Cash address is assembled byte by byte at runtime through Vec::push before its XOR decode with seed 0xb57f3ff7, which keeps it out of a strings dump of the file.

The regular expressions are written to match address formats, the replacement is written back to the pasteboard instead of being recorded, and the substituted addresses are attacker-controlled and checksum-valid. A victim who copies a payment address, pastes it into a wallet and confirms sends the funds to the operator. That path needs no password, no browser profile and no Full Disk Access grant, and the transaction settles on the blockchain before the victim has reason to re-read the address.

Negative findings

No process-injection primitive appears in the enumerated dlopen and dlsym sites. The module loader runs code in the sample's own process and does not write into another.

The Full Disk Access dialog is social engineering. It requests an entitlement the victim grants in System Settings, and no flaw is exploited to obtain it.

Analysis

The discovery of this x86_64 build provides concrete evidence regarding the maturity of the operator’s distribution pipeline. Rather than representing an intentional pivot toward legacy Intel hardware, this sample constitutes one slice of a multi-architecture fat binary (SHA-256 a4537baf). The presence of both slices indicates that the threat actor has integrated universal compilation targets into their builder to ensure automated, friction-free infection regardless of the underlying host processor.

This toolchain expansion exposes a critical operational gap in enterprise detection engineering. Threat intelligence published following the initial July 2026 disclosures focused almost exclusively on the arm64 slice. Because the macOS kernel selects and executes only the architecture slice native to the local hardware, an Intel Mac executing this fat binary exhibits different static hashes, distinct code-signing hashes (CDHash), and divergent memory layout offsets than an Apple Silicon host. Organizations relying on single-architecture hashes or brittle byte signatures derived solely from arm64 reporting face a functional blind spot across their remaining Intel-based fleet.

The integration of smart contract lookups—commonly tracked as EtherHiding—shifts infrastructure resilience fundamentally in favor of the operator. By issuing JSON-RPC eth_call requests querying ERC-20 name() records across public, high-volume providers (llamarpc, publicnode, drpc, 1rpc), the malware establishes a resilient, decentralized dead-drop resolver.

The deployment of a two-tiered persistence mechanism underscores the author's intent to survive diverse operating system baselines. By invoking modern SMAppService APIs alongside a decrypted Mach-O helper utilizing deprecated LSSharedFileList functions, the stealer establishes dual footholds.

This architecture creates a severe remediation hazard for automated incident response workflows. Modern security tooling operating on newer macOS releases typically interrogates Background Task Management structures. Removing the primary SMAppService registration cleans the active configuration but leaves the secondary entry under kLSSharedFileListSessionLoginItems intact. On systems supporting legacy login lists, this dormant helper executes upon the next user session, reactivating the intrusion. Complete eradication demands concurrent enumeration and eviction across both modern service tables and legacy shared-file lists.

Sample details

Field Value
SHA-256 9ac76794c37798420a052fbe21066f8e790ba4574f540543bb6e924a1e3d47d7
Type Mach-O thin, x86_64
Language Rust
Size 1,013,216 bytes. The delivery archive is 318,272 bytes
Image span 0x100000000 to 0x1000f9540, 1,722 functions
Code signature ad hoc, TeamIdentifier not set
CDHash 8c625b23591bae69b278ef9e472062f63f83cd2f
Signing identifier macos-stealer-v2-555549446f56834de0d13da4bdbafa7f51003efb
Campaign tag i2
Parent the x86_64 slice of a fat binary, SHA-256 a4537baf, 2,010,608 bytes

Indicators

Network

Indicator Role
hxxps://flylikeabirdmyhoneypie[.]com/api/sync Primary C2, POST application/json, body {"data":"<base64>"}
ethereum-rpc.publicnode[.]com Ethereum JSON-RPC read
eth.llamarpc[.]com Ethereum JSON-RPC read
1rpc[.]io/eth Ethereum JSON-RPC read
eth.drpc[.]org Ethereum JSON-RPC read
0x06fdde03 ERC-20 name() selector carried in the eth_call

Files

Indicator Role
9ac76794c37798420a052fbe21066f8e790ba4574f540543bb6e924a1e3d47d7 This sample
29ef90f7a64dda3d8bfdb873914a8f89b9c8b5acb5c1f829c94f8f766447f35c Embedded login-item helper, 15,744 bytes, decrypted. Recompiled per build

Cryptographic material

Indicator Role
0x5683e90cf090d568 Clean-host configuration key seed
0x553a0bc0543b79b8 Accumulator initial value in __data
e8e6a82f588783d0639f51245f353cffaff03e243c6b50cc20f9c5673c64515b 32-byte configuration key, candidate exfil key

Cryptocurrency addresses, with provenance

Address Coin Provenance
0xd29c255988e44134c4dF81627D03eEf4D7B15E10 Ethereum Configuration blob, Poly1305 authenticated. Native to this build
bitcoincash:qzjl0rs07skraanpdln8vmva73sdgylz6sq920569m Bitcoin Cash Built at runtime, checksum valid. Native to this build
0xF8220BeCdecB874437830F135769D98628Ff0F78 Ethereum Obfuscated string table
bc1q45km0u2v7epj87qhwq4kn3dmg2sw6c5n47ww7f Bitcoin Hand-decoded, not reproduced against this build
ltc1qlv2p2jpeud965unthe422vf7gk2tk8qc0mvg6d Litecoin Hand-decoded, not reproduced against this build
ltc1quyymku0d9verfll00xjv45wkfxls65vmkedrge Litecoin Hand-decoded, not reproduced against this build
LRVpwZcudFdi83yyz1PwsCiGodWY2h3ibp Litecoin Hand-decoded, not reproduced against this build
CdYdYdbA71jVDHW6UiSYixmv3twj5NL9asr2wPxJRDvY Solana Hand-decoded, not reproduced against this build
u1g3a3gnq5vzddl3yanh5ee9gtmd0747nxld25hu7s0rgdvnqgtk5c0jqszfeyvf53rrfuwrvgr4xtdks326jtk86s00lutmxscq6z5utu Zcash Hand-decoded, not reproduced against this build
45cg2g2euwMaCMvRmrJn7FHG8aQWQQGQDBUJ884BafzrGzFRVFUKEBAWZqr2FjPpbEUEz48oChhtuYsXV6SGgxNSB3dRtCt Monero Hand-decoded, not reproduced against this build

Geofence strings

Indicator Role
Asia/Novosibirsk, Asia/Tomsk, Asia/Yakutsk, Asia/Ust-Nera, Asia/Aqtau, Asia/Bishkek, Asia/Dushanbe, Asia/Tashkent, Asia/Samarkand, Asia/Ashgabat, Europe/Simferopol, Europe/Tiraspol Timezone denylist
be_, hy_, ky_, az_, uz_, tk_ Locale prefix denylist

MITRE ATT&CK

Tactic Technique Evidence
Defense Evasion Obfuscated Files or Information (T1027) Per-string XOR plus an XChaCha20-Poly1305 configuration vault
Defense Evasion Environmental Keying (T1480.001) Key seed folded from eight anti-analysis checks
Defense Evasion Debugger Evasion (T1622) sysctl P_TRACED, _dyld_debugger_notification
Defense Evasion Virtualization or Sandbox Evasion (T1497.001) IORegistry lookups for VMware, VirtualBox, Parallels, VirtIO
Defense Evasion Time Based Evasion (T1497.003) nanosleep backed by ud2
Defense Evasion Masquerading, Match Legitimate Name (T1036.005) com.apple.* identifier built from a word bank
Defense Evasion Indicator Removal, File Deletion (T1070.004) file_unlink_selfdelete
Discovery System Location Discovery (T1614.001) Timezone, locale and country checks
Discovery System Information Discovery (T1082) Serial number, CPU brand, core count, display size
Credential Access Input Capture, GUI Input Capture (T1056.002) NSAlert with NSSecureTextField
Credential Access Modify Authentication Process, PAM (T1556.003) pam_start, pam_authenticate, pam_end
Credential Access Credentials from Web Browsers (T1555.003) Chromium and Gecko credential stores
Credential Access Credentials from Password Stores, Keychain (T1555.001) Safe Storage service-name lookups. Mechanism unconfirmed
Collection Data from Local System (T1005) SQLite reads and file staging
Collection Clipboard Data (T1115) NSPasteboard polled through changeCount
Persistence Boot or Logon Autostart Execution (T1547) SMAppService login item and an LSSharedFileList helper
Execution Native API (T1106) NSURLSession, posix_spawnp, dlopen
Command and Control Application Layer Protocol, Web (T1071.001) HTTPS POST of {"data":"<base64>"}
Command and Control Web Service, Dead Drop Resolver (T1102.001) eth_call for ERC-20 name() decrypted as configuration
Command and Control Ingress Tool Transfer (T1105) Module fetched and loaded through dlopen
Exfiltration Exfiltration Over C2 Channel (T1041) Chunked tar.gz upload with an upload_init handshake
Impact Financial Theft (T1657) Clipboard address substitution

Recent Articles

Featured image: Inside MSP Billing: What actually happens to your margin, day by day
Gregory Rogers • 5 min read

Inside MSP Billing: What actually happens to your margin, day by day

There's one number that decides whether your MSP business makes money: the spread. What you pay for your technology and what you charge your clients. The gap between the two is your entire business.

Product News
Featured image: Introducing macOS LAPS in Iru: Secure, automated local admin passwords
Mike Boylan • 4 min read

Introducing macOS LAPS in Iru: Secure, automated local admin passwords

Local administrator accounts are indispensable for troubleshooting and recovery, but the passwords behind them can also become a serious security liability. Shared credentials, long or nonexistent rotation intervals, and inconsistent storage practices give attackers more time and opportunity to move laterally after a compromise.

Product News
Featured image: Apple OS 27 is here. Iru is ready.
Adam Henry • 8 min read

Apple OS 27 is here. Iru is ready.

Apple's OS 27 releases are available now, bringing new management capabilities across iPhone, iPad, Mac, Apple TV, and Vision.

Product News

See Iru in action

Discover why thousands of teams choose Iru

By submitting this form I agree to Iru’s Privacy Policy and consent to be contacted by Iru about its products and services.

Stay up to date

Iru's bi-weekly collection of articles, videos, and research to keep IT & Security teams ahead of the curve.