Skip to content

Replace Play Integrity Fix with LSPosed + honest integrity copy#59

Merged
RobThePCGuy merged 1 commit into
masterfrom
feature/lsposed
Jul 20, 2026
Merged

Replace Play Integrity Fix with LSPosed + honest integrity copy#59
RobThePCGuy merged 1 commit into
masterfrom
feature/lsposed

Conversation

@RobThePCGuy

Copy link
Copy Markdown
Owner

Cuts the (unmerged) Play Integrity Fix feature and adds LSPosed instead, plus corrects integrity copy that overclaimed.

Why cut PIF

On BlueStacks a green Play Integrity verdict isn't reachable — Google gates emulator integrity to MEETS_VIRTUAL_INTEGRITY, which is exclusive to Google Play Games. We confirmed it empirically (root hidden via MagiskHide + fresh Pixel fingerprint spoofing in DroidGuard + fresh security patch + a clean GMS still returns no verdict), and no BlueStacks rooter — including the polished competitors — claims to pass it. Shipping a PIF button implied a capability the platform can't deliver.

What's added

  • lsposed_payload.py: pinned, hash-locked LSPosed v1.9.2 (7024) zygisk variant, download-at-runtime, mirroring the ReZygisk payload.
  • Magisk tab: Install LSPosed (Xposed) button (fetch → install_module), shown once the manager is installed, like ReZygisk. Needs ReZygisk (Zygisk) first.
  • Rewrote the module note: it no longer says Basic/Device are "within reach." Honest framing — these modules give root, Zygisk, and Xposed, not Play Integrity, which does not pass on an emulator.
  • README: dropped "Play Integrity Fix" from the module lists and added the integrity caveat.

155 tests green.

Cut the PIF feature (never merged): on BlueStacks a green Play Integrity
verdict isn't reachable — Google gates emulator integrity to
MEETS_VIRTUAL_INTEGRITY, exclusive to Google Play Games — so a PIF button
implied a capability the platform can't deliver. Confirmed empirically
(root hidden + fresh fingerprint + fresh security patch + clean GMS still
returns no verdict) and by the competition (no BlueStacks rooter claims it).

Instead add LSPosed, which actually works on our stack:
- lsposed_payload.py: pinned, hash-locked LSPosed v1.9.2 (7024) zygisk
  variant, download-at-runtime, mirrors the ReZygisk payload.
- Magisk tab: "Install LSPosed (Xposed)" button (fetch -> install_module),
  gated on the manager like ReZygisk; needs ReZygisk (Zygisk) first.
- Rewrite the module note to stop claiming Basic/Device are "within reach":
  these modules give root, Zygisk, and Xposed — not Play Integrity, which
  does not pass on an emulator.
- README: drop "Play Integrity Fix" from the module lists; add the honest
  integrity caveat.

155 tests green.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for downloading, verifying, and installing the LSPosed (Zygisk) module on BlueStacks instances, including UI integration and unit tests. The reviewer recommends replacing urllib.request.urlretrieve with urllib.request.urlopen and an explicit timeout to prevent potential hanging on unstable network connections, along with corresponding updates to the unit tests to mock urlopen instead of urlretrieve.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread lsposed_payload.py
_p("Downloading LSPosed (%s)..." % MODULE_NAME)
tmp = dest + ".part"
try:
urllib.request.urlretrieve(MODULE_URL, tmp) # pinned URL, hash-checked below

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using urllib.request.urlretrieve without a timeout can cause the background thread to hang indefinitely if the network connection is unstable or the server is unresponsive. It is highly recommended to use urllib.request.urlopen with an explicit timeout parameter instead, reading the response in chunks to write to the temporary file.

        with urllib.request.urlopen(MODULE_URL, timeout=30) as response:
            with open(tmp, "wb") as f:
                for chunk in iter(lambda: response.read(1 << 20), b""):
                    f.write(chunk)


def _boom(*a, **k):
raise AssertionError("fetch_module downloaded despite a valid cached file")
monkeypatch.setattr(lp.urllib.request, "urlretrieve", _boom)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since we updated fetch_module to use urllib.request.urlopen instead of urlretrieve, we should update this mock to target urlopen to ensure the test continues to pass.

Suggested change
monkeypatch.setattr(lp.urllib.request, "urlretrieve", _boom)
monkeypatch.setattr(lp.urllib.request, "urlopen", _boom)

Comment on lines +47 to +50
def fake_dl(url, dest):
with open(dest, "wb") as f:
f.write(good)
monkeypatch.setattr(lp.urllib.request, "urlretrieve", fake_dl)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update this mock to target urllib.request.urlopen using io.BytesIO to simulate the network response.

    import io
    monkeypatch.setattr(lp.urllib.request, "urlopen", lambda url, timeout=None: io.BytesIO(good))

Comment on lines +59 to +62
def _fake_download(url, dest):
with open(dest, "wb") as f:
f.write(b"corrupted-or-tampered")
monkeypatch.setattr(lp.urllib.request, "urlretrieve", _fake_download)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update this mock to target urllib.request.urlopen using io.BytesIO to simulate the corrupted network response.

    import io
    monkeypatch.setattr(lp.urllib.request, "urlopen", lambda url, timeout=None: io.BytesIO(b"corrupted-or-tampered"))

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d13c5c4305

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread views/magisk_page.py
self.manager_button.setVisible(installed and not manager)
self.remove_manager_button.setVisible(manager)
self.rezygisk_button.setVisible(manager)
self.lsposed_button.setVisible(manager)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide LSPosed on unsupported Android 7 instances

The pinned LSPosed v1.9.2 supports Android 8.1–14, but this exposes the install action solely based on manager presence. For the Nougat 32/64 instances that this project explicitly supports, clicking it downloads and attempts to flash a module that cannot run on Android 7. Gate the action using the instance Android version, or reject those instances with a clear compatibility message.

Useful? React with 👍 / 👎.

@RobThePCGuy
RobThePCGuy merged commit 5cbee61 into master Jul 20, 2026
4 checks passed
@RobThePCGuy
RobThePCGuy deleted the feature/lsposed branch July 20, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant