{"slug": "a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it", "title": "A 27B Model That Reverse-Engineered a License Check (And How to Run It)", "summary": "A 27B-parameter open-weights model, Qwen3.8-27B, reverse-engineered a commercial application's license check by recovering an obscured crypto key from ARM64 assembly and producing a working bypass proof-of-concept in about 30 minutes on a desktop computer, according to an XDA article. The author, who owns an ASUS Ascent GX10 with the same GB10 silicon, provides a setup guide for running the model, including disk space requirements, memory management, and OS configuration.", "body_md": "XDA ran a piece that stopped me mid-scroll: [a 27B open-weights model reverse-engineered a commercial application’s license check](https://www.xda-developers.com/qwen-3-8-27b-reverse-engineering-job-frontier-model/) — recovered a deliberately obscured crypto key out of ARM64 assembly, caught and corrected its own mistake without being told, and produced a working bypass PoC. In about thirty minutes. On a desktop box. I have (a version of) that box. So I went and set it up.\n\nThe model is **Qwen3.8-27B**. Artificial Analysis has it as the top open-weights model in the 4B–40B class out of 135 models, at 52 on their intelligence index. The hardware in the article was a Lenovo ThinkStation PGX — NVIDIA Grace Blackwell, 128 GB unified memory, 273 GB/s. Mine is an [ASUS Ascent GX10](https://www.asus.com/us/networking-iot-servers/desktop-ai-supercomputer/ultra-small-ai-supercomputers/asus-ascent-gx10/), which is the same GB10 silicon in a different box.\n\nI’ve been building toward this for a while. In May I wrote that [AI inference costs are the wake-up call for 2026 and 2027](https://blog.herlein.com/post/ai-inference-costs-reality-check/). In July I argued that [tokens should be NRE, not COGS](https://blog.herlein.com/post/tokens-are-nre-not-cogs/). Earlier this month I [benchmarked the GX10 against a ZBook Ultra G1a](https://blog.herlein.com/post/gx10-vs-zbook-g1a-coding-agent/) on a real agentic coding task and came away convinced the small box is the one you actually reach for.\n\nThis post is the missing piece: the actual setup. What follows is the recipe I ran, corrected against a real GX10 bring-up, including the parts that bit me.\n\n## Before You Start: Two Things That Will Ruin Your Day\n\n**Disk.** You need about 100 GB free. The base container image alone is 57 GB, weights are ~19 GB, caches on top of that.\n\n```\ndf -h ~\n```\n\n**Free the unified memory first.** This is the one that got me. SGLang runs at `--mem-fraction-static 0.90`\n\n, which claims ~90% of system RAM. Anything else already resident will collide — and on GB10 that collision doesn’t produce a nice error, it produces a **hard reboot** during CUDA-graph capture.\n\nThe usual culprit is `ollama`\n\n, which pins its model in unified memory and sits there.\n\n```\nnvidia-smi                    # check the Processes list at the bottom\nsudo systemctl stop ollama\nsudo systemctl disable ollama # stop it grabbing memory on boot\nnvidia-smi                    # want: \"No running processes found\"\nfree -h                       # want: ~100+ GB free\n```\n\nGB10 quirk:`nvidia-smi`\n\nreports`Memory-Usage: Not Supported`\n\nin the summary table. That’s normal for unified memory — it’s not broken. Read theprocess listat the bottom, or use`free -h`\n\n.\n\nAlso note `free -h`\n\nshows about **121 GB**, not 128 — firmware and system reserve the rest. At 0.90 that means SGLang takes ~109 GB with comfortable headroom. Don’t “fix” this. `0.95`\n\nreboots the box.\n\n## OS and Stack Check\n\nThe GX10 ships DGX OS, but a stock **Ubuntu 24.04 LTS (arm64)** install works fine and is fully supported — driver, CUDA, Docker, Container Toolkit all run natively. Mine’s Ubuntu. Confirm what you have:\n\n```\ncat /etc/os-release     # Ubuntu 24.04 (noble) or DGX OS — either is fine\ndocker version          # arm64 engine; 29.x is current\nnvidia-ctk --version    # NVIDIA Container Toolkit present\nnvidia-smi              # GB10 visible, driver loaded\n```\n\nA healthy box: `NVIDIA GB10`\n\n, driver 580.x, CUDA 13.x, Docker 29.x `linux/arm64`\n\n, Container Toolkit 1.19.x. If Docker or the toolkit are missing:\n\n```\nsudo apt update\nsudo apt install -y docker.io\nsudo systemctl enable --now docker\nsudo usermod -aG docker \"$USER\"          # log out and back in after this\nsudo nvidia-ctk runtime configure --runtime=docker\nsudo systemctl restart docker\n```\n\nOptionally set a Hugging Face token for faster pulls:\n\n```\necho 'export HF_TOKEN=hf_xxxxxxxxxxxxxxxxx' >> ~/.bashrc && source ~/.bashrc\n```\n\n## Clone and Configure\n\n```\ncd ~\ngit clone https://github.com/MiaAI-Lab/Qwen3.8-27B-SGLang-DGX-Spark.git\ncd Qwen3.8-27B-SGLang-DGX-Spark\ncp .env.sample .env\n```\n\nThe defaults are sane for code work: NVFP4 weights, native 262K context, YaRN off, 16 concurrent requests.\n\n**One hard rule: keep YARN=0 and CONTEXT_LENGTH=262144.** DFlash2 is not compatible with YaRN context extension on this build. A larger context leaking into the draft config throws\n\n`AttributeError ... max_position_embeddings`\n\nat boot and you’ll spend an hour thinking it’s a driver problem. Confirm before you launch:\n\n```\ngrep -E '^YARN|^CONTEXT_LENGTH' .env\n```\n\nAlso: the repo hardcodes `PORT=8888`\n\nand `SERVED_MODEL_NAME=qwen3.8-27b-sglang`\n\n. Overriding either one requires patching `start.sh`\n\n. I didn’t bother — I use 8888 and read the served model id from `/v1/models`\n\n. (The patch is a two-line change if you want it; I put it at the end.)\n\nOne caveat worth saying out loud: **this upstream repo is new and moving.** Sanity-check script names and `.env`\n\nkeys against the current README before you run anything. Don’t trust my transcription over their repo.\n\n## Build and Launch\n\nBuild the DFlash2 image — a pure local overlay onto the pinned SGLang image, with every overlaid file checksum-verified:\n\n``` php\n./patch/build-dflash2-image.sh --minimal\n# -> lmsysorg/sglang:qwen38-27b-dflash2-minoverlay\n```\n\nFirst run pulls ~57 GB. Go do something else. Take a nap. Or a walk. It takes a bit, even with a fast network.\n\nThen launch:\n\n```\nDF_EXTRA=\"--sleep-on-idle\" \\\nIMAGE=lmsysorg/sglang:qwen38-27b-dflash2-minoverlay \\\n./start-dflash.sh\n```\n\n`--sleep-on-idle`\n\nmatters more than it looks. Without it the SGLang scheduler busy-spins at ~97% CPU doing *nothing*, which on a small fanless-ish box you can hear and feel.\n\nFirst boot downloads weights and compiles kernels: **10–20 minutes, mostly silent.** Weight load alone is about 5 minutes. Warm restarts are 2–3 minutes. Watch it in another pane:\n\n```\ntail -f .sglang.log\n```\n\nYou’re up when you see `Uvicorn running on http://0.0.0.0:8888`\n\nand `Application startup complete`\n\n.\n\n## Verify\n\nFair warning on the first thing that’ll confuse you: `curl -s`\n\nswallows connection errors, so an empty reply piped to `json.tool`\n\ngives you `Expecting value: line 1 column 1`\n\n. That almost always means **not listening yet**, not crashed. Check `docker ps`\n\nand the log before you panic.\n\n```\nPORT=8888\n\n# Is it up? Also grabs the real served model id.\nMODEL=$(curl -s http://127.0.0.1:$PORT/v1/models \\\n  | python3 -c 'import sys,json;print(json.load(sys.stdin)[\"data\"][0][\"id\"])')\necho \"Serving model id: $MODEL\"\n\n# A code-shaped call with thinking OFF — the fast lane:\ncurl -s http://127.0.0.1:$PORT/v1/chat/completions \\\n  -H 'Content-Type: application/json' -d \"{\n    \\\"model\\\": \\\"$MODEL\\\",\n    \\\"messages\\\": [{\\\"role\\\":\\\"user\\\",\\\"content\\\":\\\"Write an idiomatic Go function that returns the nth Fibonacci number iteratively.\\\"}],\n    \\\"max_tokens\\\": 300,\n    \\\"temperature\\\": 0.2,\n    \\\"chat_template_kwargs\\\": {\\\"enable_thinking\\\": false},\n    \\\"stream_options\\\": {\\\"include_usage\\\": true}\n  }\" | python3 -m json.tool\n```\n\nLogs are `tail -f .sglang.log`\n\nor `docker logs -f qwen3.8-27b-sglang`\n\n. Stop with `./stop.sh`\n\n.\n\n## Pointing Your Agents At It\n\nThe server exposes three protocols on `http://<gx10-ip>:8888`\n\n:\n\n**OpenAI Chat Completions**—`/v1/chat/completions`\n\n, works out of the box**OpenAI Responses**—`/v1/responses`\n\n, needs a compat patch for strict SDK clients**Anthropic-style**—`/v1/messages`\n\nFor **OpenAI-compatible agents** — aider, opencode, Cline, Continue, and the ones I’ve been [testing lately](https://blog.herlein.com/post/skills-mapper-sm/):\n\n```\nexport OPENAI_BASE_URL=\"http://<gx10-ip>:8888/v1\"\nexport OPENAI_API_KEY=\"sk-local\"     # any non-empty string; the server ignores it\n```\n\naider, concretely:\n\n```\naider --openai-api-base http://<gx10-ip>:8888/v1 \\\n      --openai-api-key sk-local \\\n      --model openai/qwen3.8-27b-sglang\n```\n\n**Claude Code** speaks the Anthropic protocol and `/v1/messages`\n\nis right there:\n\n```\nexport ANTHROPIC_BASE_URL=\"http://<gx10-ip>:8888\"\nexport ANTHROPIC_API_KEY=\"sk-local\"\n```\n\nTreat that one as best-effort. This build 400s on some exotic Responses/message item types — MCP tool-call echoes, `web_search_call`\n\nechoes, `item_reference`\n\n. Plain function tools and chat work fully. For predictable agentic coding *today*, the OpenAI-compatible path is the tested one.\n\nBy the way — the XDA reverse-engineering run used the `pi`\n\nharness, which is worth knowing. The harness matters as much as the endpoint. I’ve made [that argument at length](https://blog.herlein.com/post/dot-agents/).\n\n## The Explicit `docker run`\n\nIf you’d rather own every flag than trust a launcher — and honestly, for something you’re going to run every day, you should read this at least once:\n\n```\nPORT=8888\nIMAGE=lmsysorg/sglang:qwen38-27b-dflash2-minoverlay\nCACHE=$HOME/Qwen3.8-27B-SGLang-DGX-Spark/.cache\n\ndocker run -d --name qwen38-code \\\n  --network host --ipc host --privileged --gpus all --shm-size 32g \\\n  -e HF_HOME=/root/.cache/huggingface \\\n  -e TRITON_CACHE_DIR=/root/.triton \\\n  -v ${CACHE}/huggingface:/root/.cache/huggingface \\\n  -v ${CACHE}/triton:/root/.triton \\\n  ${IMAGE} python3 -m sglang.launch_server \\\n    --model-path RadixArk/Qwen3.8-27B-NVFP4 \\\n    --served-model-name qwen38-27b --trust-remote-code \\\n    --tp 1 \\\n    --attention-backend flashinfer --chunked-prefill-size 8192 \\\n    --disable-prefill-cuda-graph --kv-cache-dtype fp8_e4m3 \\\n    --mamba-ssm-dtype bfloat16 --mamba-full-memory-ratio 4.21 \\\n    --mamba-radix-cache-strategy extra_buffer \\\n    --max-mamba-cache-size 64 --max-running-requests 16 \\\n    --context-length 262144 \\\n    --speculative-algorithm DFLASH \\\n    --speculative-draft-model-path z-lab/Qwen3.8-27B-DFlash2 \\\n    --speculative-draft-model-revision 50307d4c4cde6860d4eee73e2547cd786fe8e8a4 \\\n    --speculative-num-draft-tokens 8 \\\n    --reasoning-parser qwen3 --tool-call-parser qwen3_coder \\\n    --sampling-defaults model --enable-metrics --enable-cache-report \\\n    --stream-interval 1 --sleep-on-idle \\\n    --mem-fraction-static 0.90 --host 0.0.0.0 --port ${PORT}\n```\n\nThe flags that actually matter for code: `--speculative-num-draft-tokens 8`\n\n(block size), `--tool-call-parser qwen3_coder`\n\n(agent function calls — you need this), `--stream-interval 1`\n\n(per-token SSE), `--mem-fraction-static 0.90`\n\n(the safe headroom), `--kv-cache-dtype fp8_e4m3`\n\n(keeps KV memory sane at 262K context).\n\nSetting `--served-model-name qwen38-27b`\n\nhere makes the model id `qwen38-27b`\n\nregardless of the repo default — which is the easy way around the port/name patch if you’re going explicit anyway.\n\n## Conclusion\n\nHere’s what I keep circling back to.\n\nA 27B model, quantized to 4 bits, running locally, did a static reverse-engineering job on ARM64 assembly — including *catching its own error and fixing it* — in thirty minutes. Unattended. Off the network.\n\nThat is not the story the “local models are toys” crowd has been telling. It’s also not the story the “you need a trillion parameters” crowd has been telling. Both of them are about to be wrong in the same direction, and I’ve said before that [today’s models are the worst you’ll ever use](https://blog.herlein.com/post/agent-naysayers/).\n\nI’m not claiming this replaces a frontier model for everything. It doesn’t, and I’ll write that post honestly when I’ve run it against enough real work. What I *am* claiming is that the line between “send this to the cloud” and “run this locally” moved, again, and it moved further than I expected it to this quarter. Every time it moves, the NRE-versus-COGS math gets better for owning the hardware.\n\nSetup is an afternoon, most of it waiting on a 57 GB pull. Go run it and find out where your own line is.\n\n**What’s next for me:** running this endpoint under the coding agents I’ve been evaluating, and seeing whether a local 27B holds up in a real agentic loop the way it did on a single well-scoped analysis task. Those are very different asks. That’s the post I actually want to write.\n\nCredit where it’s due: the XDA piece by way of Artificial Analysis’s benchmarks is what sent me down this road, and the [MiaAI-Lab repo](https://github.com/MiaAI-Lab/Qwen3.8-27B-SGLang-DGX-Spark) is doing the unglamorous packaging work that makes this a one-afternoon job instead of a one-week job.\n\nIf you get this running — or if you hit something my troubleshooting table doesn’t cover — drop me a note on LinkedIn: [linkedin.com/in/gherlein](https://www.linkedin.com/in/gherlein/). I’ll add it.", "url": "https://wpnews.pro/news/a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it", "canonical_source": "https://blog.herlein.com/post/qwen38-27b-gx10-setup/", "published_at": "2026-08-23 08:00:02+00:00", "updated_at": "2026-08-23 18:13:16.251894+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools"], "entities": ["Qwen3.8-27B", "XDA", "Lenovo ThinkStation PGX", "NVIDIA Grace Blackwell", "ASUS Ascent GX10", "NVIDIA GB10", "Ubuntu 24.04 LTS", "Hugging Face"], "alternates": {"html": "https://wpnews.pro/news/a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it", "markdown": "https://wpnews.pro/news/a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it.md", "text": "https://wpnews.pro/news/a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it.txt", "jsonld": "https://wpnews.pro/news/a-27b-model-that-reverse-engineered-a-license-check-and-how-to-run-it.jsonld"}}