79 Commits
Author SHA1 Message Date
dependabot[bot] 16f21b44ae Bump actions/setup-node from 6 to 7 2026-09-05 10:45:20 +02:00
pancake 2121fed687 Refresh the tournament stats while running 2026-08-31 22:34:29 +02:00
pancake cef1c7a097 Share webui between c# and ts engines 2026-08-31 22:27:57 +02:00
pancake 84dd048b84 Add a bot editor 2026-08-31 22:00:48 +02:00
pancake 672df06cf4 Improved README 2026-08-31 21:35:41 +02:00
pancake 508db1c2bc Initial support for running in wasm 2026-08-31 21:24:23 +02:00
pancake 097f9405f6 Pin r2 version and fix dockerfiles 2026-08-29 03:43:10 +02:00
pancake 915869ddd4 Port to dotnet.10 and remove nuget because all deps are in stock dotnet 2026-08-29 03:37:48 +02:00
pancake 120a0c2502 Ci release and codeql fixes 2026-08-29 03:04:52 +02:00
dependabot[bot] 30558ea731 Bump github/codeql-action from 2 to 4 2026-08-29 03:04:42 +02:00
pancake c97fd325f2 Add github release on numeric tags 2026-08-29 02:52:12 +02:00
dependabot[bot] 14a092e536 Bump actions/checkout from 3 to 7 2026-08-29 02:49:30 +02:00
pancake 85d4ec3b49 Add dependabot 2026-08-29 02:48:22 +02:00
LGTM Migrator 756700f93b Add CodeQL workflow for GitHub code scanning 2026-08-29 02:47:51 +02:00
pancake 9313756380 Release 0.4.0 2026-08-29 02:41:08 +02:00
pancake 80ea942513 Add ci workflow 2026-08-29 02:23:14 +02:00
pancake 1002399ce9 Fix prev/next states and overall competition flow UX 2026-08-29 02:18:00 +02:00
pancake f493c3706d Fix build and run with latest r2 2026-08-29 00:44:14 +02:00
Eduard Vlad 29e37fe36d Pin version for Ubuntu to 22.04 2024-06-10 22:34:58 +02:00
Florian Hofhammer 3828a549c2 Add Makefile to wrap around docker compose 2023-06-05 10:17:51 +02:00
Florian Hofhammer 36b0f07c0c Set timezone to UTC and make r2 source a build arg 2023-06-05 10:17:51 +02:00
Florian Hofhammer 1834ea4f11 Add .dockerignore to restrict the build context
Only the csharp directory is important for a Docker build. Without
the .dockerignore, Docker recognizes a change in the build context
and doesn't use the build cache nicely even if just the warriors
are changed.
2023-06-05 10:17:51 +02:00
Florian Hofhammer 347bba1441 Use multi-stage Docker builder and Docker compose
The multi-stage Docker builder makes better use of caching and
builds r2 and r2wars independently.
Docker compose allows easy building ("docker compose build") and
running ("docker compose up").
2023-06-05 10:17:51 +02:00
Florian Hofhammer 4b55638d2c Fix typos 2023-06-05 10:17:51 +02:00
Florian Hofhammer 5936113029 Increase initstate size to not crash
The fixed size for the initstate caused accesses out of the array's
bounds when using architectures added later on (e.g., RISC-V).
The correct initstate size fixes this and lets us use newly added
archs as well.
2023-06-05 10:17:51 +02:00
Collin Reilly Clark 86854d490d execute start.sh using bash instead of sh -- also catches SIGINT to cleanly shut down server (#12) 2022-09-20 16:11:26 +02:00
sanguinawer 7820cc36e2 2021 bots 2021-10-04 22:26:28 +02:00
pancake d4d4c595da Add support for RISCV-32 and RISCV-64 (#10) 2021-09-29 00:25:00 +02:00
pancake 91686018a2 Use temporal seek instead of seek;cmd (#9) 2021-09-29 00:06:01 +02:00
sanguinawer 02430027f8 fixed tournament crash with new r2 versions 2021-09-26 02:22:22 +02:00
pancake 9be5d63861 Update docker image and start scripts 2021-06-10 19:31:45 +02:00
ps1337 6777a5134e add experimental docker image 2021-06-09 20:36:47 +02:00
BananaBoii 6317137aaa Add r2con2020 talk to README.md 2021-06-06 20:31:50 +02:00
pancake 0d5458bdd1 Fix r2wars.v build with latest V 2020-11-14 00:53:28 +01:00
pancake c445b3b145 Add bots from r2con2020 2020-09-11 11:51:10 +02:00
pancake feb51c621d Add original python implementation 2020-09-08 16:54:06 +02:00
pancake 7cd63a3210 Dead by ill type 2020-09-08 10:15:54 +02:00
pancake 0c5affe865 Parse commandline, improve stats and more 2020-09-08 03:27:43 +02:00
pancake 63166db01a Fix logo url 2020-09-08 02:30:47 +02:00
pancake 65df30022c Add examples symlink 2020-09-08 02:29:56 +02:00
pancake a6125a22f5 Move c# code into csharp/ direcctory 2020-09-08 02:29:22 +02:00
pancake 5cbd827822 Initial implementation in V 2020-09-08 02:25:33 +02:00
BananaBoii 23e506cd65 add r2wars logo (#7) 2020-09-07 12:41:10 +02:00
sanguinawer 0aa7a5e617 changes for r2con 2020 2020-09-05 18:35:31 +02:00
sanguinawer 5e683c2794 optimized memory leaks on firefox 2020-08-29 19:46:58 +02:00
sanguinawer c9c4702b37 pad 2020-08-26 00:41:13 +02:00
sanguinawer a454e45679 fixed html 2020-08-26 00:23:57 +02:00
sanguinawer 3dd1ae6257 fixed r2pipe for windows 2020-08-25 14:40:47 +02:00
Jannis 4236326c89 Fix #4 - Added custom version detection (#5) 2020-07-06 13:59:05 +02:00
hmht 03e0f6fc77 Allow 8051 bots (#6)
bots named *.8051.* will run with shared code and xdata memory space,
allowing them to write to the arena.
2020-07-06 13:58:34 +02:00
pancake 448c0f014b Make combat results dialog a bit wider 2019-09-07 15:41:42 +02:00
pancake 41f866157a Reduce cycles to 2k to avoid 2 min wait in stuck situations 2019-09-07 15:02:52 +02:00
pancake dd14ab1d7f Release 0.4.0 (r2con2019) 2019-09-07 10:12:10 +02:00
pancake e7f532be89 fixed legend 2019-09-07 09:31:10 +02:00
pancake fa3804da2f Improve html 2019-09-07 09:24:15 +02:00
sanguinawer b442cec725 r2wars 2k19 2019-09-04 14:32:41 +02:00
sanguinawer d9f548d0e6 changes on gui 2 2019-08-13 13:50:28 +02:00
sanguinawer 0e514bee77 changes on gui 2019-08-13 13:45:43 +02:00
sanguinawer 5ae6291f89 Merge branch 'master' of https://github.com/radareorg/r2wars 2019-08-12 20:21:23 +02:00
sanguinawer b99220cfd7 changes on tournament/combat logic 2019-08-12 20:20:33 +02:00
sanguinawer efb9dbe8cf Update README.md 2019-08-11 14:43:42 +02:00
sanguinawer 2d3639a2df r2con 2019 fix 2019-08-11 14:42:05 +02:00
sanguinawer 9381ccfb8a r2con2k19 initial fixes 2019-07-23 13:35:31 +02:00
skuater 15905b2860 ban execution out of arena 2018-09-07 20:58:32 +02:00
skuater 056c9faf71 low cycles timeout, and scroll code window 2018-09-07 18:51:38 +02:00
skuater 0d97537739 live version on r2con 2018-09-07 13:52:11 +02:00
skuater aeab41de68 change colors and pad lines for correct visualization on r2con 2018-09-07 01:47:12 +02:00
skuater 4715c10c06 fixed combats draw state 2018-09-06 15:38:29 +02:00
skuater 6a9dd887f9 setting r2 into r2wars mode 2018-09-05 19:33:00 +02:00
skuater 080d80f73d fix on pauses 2018-09-05 12:01:43 +02:00
skuater fcadb178f3 multiarch version 2018-08-27 13:04:22 +02:00
skuater 267d855063 update makefile and project name 2018-08-08 22:48:17 +02:00
skuater 186ef4d158 add .sln 2018-08-08 22:27:56 +02:00
skuater 4d818caca7 more refactoring 2018-08-06 23:27:44 +02:00
skuater 149217dc75 more refactoring 2018-08-06 20:57:16 +02:00
skuater b878b99a6d fix initial state when load warriors 2018-08-06 20:41:24 +02:00
skuater d8a265cbef deleted unused function 2018-08-06 20:21:12 +02:00
skuater 06dc00704c Merge branch 'master' of https://github.com/radareorg/r2wars 2018-08-06 20:17:45 +02:00
skuater 14e48452b5 refactoring 2018-08-06 20:17:10 +02:00
210 changed files with 13699 additions and 24642 deletions

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
# Ignore everything...
*
# ...apart from the csharp subdirectory which is the only one that's needed
!csharp/
+11
View File
@@ -0,0 +1,11 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
commit-message:
prefix: "##build "
prefix-development: "##build "
labels:
- buildsystem
+100
View File
@@ -0,0 +1,100 @@
name: Build
on:
push:
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
outputs:
is_release: ${{ steps.release.outputs.is_release }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Build Docker image
run: make build
- name: Check for a release tag
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
id: release
shell: bash
run: |
tag="$(git describe --exact-match --tags "$GITHUB_SHA" 2>/dev/null || true)"
if [[ "$tag" =~ ^[0-9] ]]; then
echo "is_release=yes" >> "$GITHUB_OUTPUT"
echo "tag_name=$tag" >> "$GITHUB_OUTPUT"
else
echo "is_release=no" >> "$GITHUB_OUTPUT"
fi
- name: Check release version
if: ${{ steps.release.outputs.is_release == 'yes' }}
env:
TAG_NAME: ${{ steps.release.outputs.tag_name }}
run: |
version=$(./version.sh)
if [ "$TAG_NAME" != "$version" ]; then
echo "Tag $TAG_NAME does not match version $version" >&2
exit 1
fi
- name: Create distribution archive
if: ${{ steps.release.outputs.is_release == 'yes' }}
env:
TAG_NAME: ${{ steps.release.outputs.tag_name }}
run: |
archive="r2wars-$TAG_NAME"
container=$(docker create r2wars:latest)
trap 'docker rm -f "$container" >/dev/null' EXIT
docker cp "$container:/r2wars/." release-bin
mkdir "$archive"
cp -R release-bin/. "$archive/"
cp -R examples "$archive/warriors"
cp RELEASE_README.md "$archive/README.txt"
zip -r "$archive.zip" "$archive"
- name: Store distribution archive
if: ${{ steps.release.outputs.is_release == 'yes' }}
uses: actions/upload-artifact@v7
with:
name: r2wars-${{ steps.release.outputs.tag_name }}
path: r2wars-${{ steps.release.outputs.tag_name }}.zip
if-no-files-found: error
release:
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && needs.build.outputs.is_release == 'yes' }}
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download distribution archive
uses: actions/download-artifact@v8
with:
name: r2wars-${{ needs.build.outputs.tag_name }}
path: release
- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ needs.build.outputs.tag_name }}
run: |
archive="release/r2wars-$TAG_NAME.zip"
if gh release view "$TAG_NAME" >/dev/null 2>&1; then
gh release upload "$TAG_NAME" "$archive" --clobber
else
gh release create "$TAG_NAME" "$archive" --verify-tag --generate-notes
fi
+39
View File
@@ -0,0 +1,39 @@
name: "CodeQL"
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
schedule:
- cron: "1 4 * * 4"
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ javascript, csharp ]
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: none
queries: +security-and-quality
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{ matrix.language }}"
+43
View File
@@ -0,0 +1,43 @@
name: WebAssembly
on:
push:
paths:
- ".github/workflows/wasm.yml"
- "csharp/wwwroot/**"
- "wasm/**"
- "Makefile"
pull_request:
paths:
- ".github/workflows/wasm.yml"
- "csharp/wwwroot/**"
- "wasm/**"
- "Makefile"
permissions:
contents: read
jobs:
test-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
cache-dependency-path: wasm/package-lock.json
- run: npm ci
working-directory: wasm
- run: npm test
working-directory: wasm
- run: npm run build
working-directory: wasm
- name: Check shared .NET client bundle
run: git diff --exit-code -- csharp/wwwroot/assets/r2wars-ui.js
- uses: actions/upload-artifact@v7
with:
name: r2wars-wasm
path: wasm/dist
if-no-files-found: error
retention-days: 7
+2
View File
@@ -0,0 +1,2 @@
csharp/bin/
csharp/obj/
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
-76
View File
@@ -1,76 +0,0 @@
using System;
using System.IO;
using System.Reflection;
using Nancy;
using Nancy.Bootstrapper;
using Nancy.Responses;
using Nancy.Session;
using Nancy.ViewEngines;
using Nancy.TinyIoc;
namespace r2warsTorneo
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
ResourceViewLocationProvider.RootNamespaces.Add(Assembly.GetAssembly(typeof(MainModule)), "r2warsTorneo.Views");
}
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
CookieBasedSessions.Enable(pipelines);
}
/*protected override void ConfigureConventions(NancyConventions conventions)
{
base.ConfigureConventions(conventions);
conventions.StaticContentsConventions.Add(AddStaticResourcePath("/content", Assembly.GetAssembly(typeof(MainModule)), "r2wars.Web.Views.content"));
}*/
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides(OnConfigurationBuilder);
}
}
void OnConfigurationBuilder(NancyInternalConfiguration x)
{
x.ViewLocationProvider = typeof(ResourceViewLocationProvider);
}
protected override byte[] FavIcon
{
get { return null; }
}
public static Func<NancyContext, string, Response> AddStaticResourcePath(string requestedPath, Assembly assembly, string namespacePrefix)
{
return (context, s) =>
{
var path = context.Request.Path;
if (!path.StartsWith(requestedPath))
{
return null;
}
string resourcePath;
string name;
var adjustedPath = path.Substring(requestedPath.Length + 1);
if (adjustedPath.IndexOf('/') >= 0)
{
name = Path.GetFileName(adjustedPath);
resourcePath = namespacePrefix + "." + adjustedPath.Substring(0, adjustedPath.Length - name.Length - 1).Replace('/', '.');
}
else
{
name = adjustedPath;
resourcePath = namespacePrefix;
}
return new EmbeddedFileResponse(assembly, resourcePath, name);
};
}
}
}
+66
View File
@@ -0,0 +1,66 @@
# syntax=docker/dockerfile:1
ARG UBUNTU_RELEASE="24.04"
ARG TIMEZONE="UTC"
ARG DOTNET_IMAGE="10.0-noble"
ARG R2_VERSION="6.2.0"
################################################################################
# Download the pinned radare2 release package #
################################################################################
FROM ubuntu:${UBUNTU_RELEASE} AS r2-package
ARG R2_VERSION
ARG TARGETARCH
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
curl
RUN case "${TARGETARCH}" in \
amd64) R2_SHA256="eb82324e83315887fbee6f5d8632c982c593e056a87180f1bec5ccb06c463aeb" ;; \
arm64) R2_SHA256="e866525e9874588d478d536cca38cf9a7562896725efb4119b886101fd93f1ec" ;; \
*) echo "Unsupported Docker architecture: ${TARGETARCH}" >&2; exit 1 ;; \
esac && \
curl --fail --location --show-error \
"https://github.com/radareorg/radare2/releases/download/${R2_VERSION}/radare2_${R2_VERSION}_${TARGETARCH}.deb" \
--output /radare2.deb && \
echo "${R2_SHA256} /radare2.deb" | sha256sum --check --strict
################################################################################
# r2wars builder #
################################################################################
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_IMAGE} AS r2wars-builder
COPY --link csharp /r2wars
WORKDIR /r2wars
RUN dotnet publish r2wars.csproj \
--configuration Release \
--output /r2wars-publish \
--no-self-contained
################################################################################
# r2wars runner #
################################################################################
FROM mcr.microsoft.com/dotnet/aspnet:${DOTNET_IMAGE} AS runner
ARG TIMEZONE
ENV TZ=${TIMEZONE}
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=bind,from=r2-package,source=/radare2.deb,target=/tmp/radare2.deb \
apt-get update && \
apt-get install -y --no-install-recommends /tmp/radare2.deb
COPY --from=r2wars-builder --link /r2wars-publish /r2wars
EXPOSE 9664 9966
WORKDIR /r2wars
ENTRYPOINT ["dotnet", "r2wars.dll"]
-40
View File
@@ -1,40 +0,0 @@
using Nancy;
namespace r2warsTorneo
{
public class MainModule : NancyModule
{
public MainModule()
{
Get["/"] = x => View["index.html"];
}
}
/*public class r2warsModule : NancyModule
{
public r2warsModule() : base("/r2wars")
{
Get["/refresh"] = x =>
{
//return r2wars.Codigo.r2wars.json_output();
return "";
};
Get["/next"] = x =>
{
//r2wars.Codigo.r2wars.btStep_Click();
//return r2wars.Codigo.r2wars.json_output();
return "";
};
Get["/start"] = x =>
{
//r2wars.Codigo.r2wars.btAuto_Click();
//return "";
return "";
};
Get["/reset"] = x =>
{
//r2wars.Codigo.r2wars.btInit_Click();
//return r2wars.Codigo.r2wars.json_output();
return "";
};
}
}*/
}
+34 -16
View File
@@ -1,20 +1,38 @@
VERSION=$(shell git tag|tail -n1)
R2W=r2wars-$(VERSION)
DOCKER ?= docker
WASM_ARCHIVE ?= r2wars-wasm.zip
all:
xbuild
.PHONY: default build start stop clean wasm-build wasm-test wasm-run wasm-dist
dist:
xbuild /p:Configuration=Release
rm -rf $(R2W)
mkdir -p $(R2W)
cp -rf examples bin/Release/*.exe bin/Release/*.dll $(R2W)
cp -f RELEASE_README.md $(R2W)/README.txt
zip -r $(R2W).zip $(R2W)
rm -rf $(R2W)
default: start ## By default, just start the container
r2w32:
wget -c http://radare.mikelloc.com/get/2.7.0/radare2_installer-msvc_64-2.7.0.exe
build: ## Build the Docker image
@$(DOCKER) compose build
clean:
rm -rf bin obj r2wars r2wars.zip
start: ## Start the container via docker compose (docker compose builds automatically if necessary)
@$(DOCKER) compose up -d
run:
$(MAKE) start
sleep 2
open http://127.0.0.1:9664/
stop: ## Tear down the container via docker compose
@$(DOCKER) compose down
clean: stop ## Remove the project containers and docker image
@if $(DOCKER) image inspect r2wars:latest >/dev/null 2>&1; then \
$(DOCKER) image rm r2wars:latest; \
fi
wasm-build: ## Build the standalone browser/WebAssembly version
cd wasm && npm install && npm run build
wasm-test: ## Test the browser engine against radare2 WebAssembly
cd wasm && npm install && npm test
wasm-run: ## Run the standalone browser/WebAssembly development server
cd wasm && npm install && npm run dev
wasm-dist: wasm-build ## Build a static-host-ready WebAssembly zip archive
cd wasm/dist && zip -qrFS "../$(WASM_ARCHIVE)" .
@echo "Created wasm/$(WASM_ARCHIVE)"
-54
View File
@@ -1,54 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using WebSocketSharp.Server;
namespace r2warsTorneo
{
static public class r2warsStatic
{
static public r2wars r2w = new r2wars();
static public Torneo torneo = new Torneo();
}
class Program
{
static void Main(string[] args)
{
string httpUrl = "http://localhost:9664";
string websocketUrl = "ws://localhost:9966";
var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
if (args.Length > 0) {
r2warsStatic.torneo.SetWarriorsDirectory(args[0]);
}
var taskA = new Task(() =>
{
var nancyHost = new Nancy.Hosting.Self.NancyHost(new Uri(httpUrl), new CustomBootstrapper());
nancyHost.Start();
Console.WriteLine("Web server running...");
Process.Start(httpUrl);
while (!ct.IsCancellationRequested) { Thread.Sleep(1000); }
nancyHost.Stop();
}, tokenSource.Token);
var taskB = new Task(() =>
{
var wssv = new WebSocketServer(websocketUrl);
wssv.AddWebSocketService<r2warsWebSocket>("/r2wars");
wssv.Start();
while (!ct.IsCancellationRequested) { Thread.Sleep(1000); }
wssv.Stop();
}, tokenSource.Token);
taskA.Start();
taskB.Start();
Console.ReadKey();
tokenSource.Cancel();
}
}
}
-36
View File
@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// La información general de un ensamblado se controla mediante el siguiente
// conjunto de atributos. Cambie estos valores de atributo para modificar la información
// asociada con un ensamblado.
[assembly: AssemblyTitle("WindowsFormsApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsFormsApplication1")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Si establece ComVisible en false, los tipos de este ensamblado no estarán visibles
// para los componentes COM. Si necesita obtener acceso a un tipo de este ensamblado desde
// COM, establezca el atributo ComVisible en true en este tipo.
[assembly: ComVisible(false)]
// El siguiente GUID sirve como id. de typelib si este proyecto se expone a COM.
[assembly: Guid("7c07ab0a-d2b5-4546-b5b2-6dc6e77e40d1")]
// La información de versión de un ensamblado consta de los cuatro valores siguientes:
//
// Versión principal
// Versión secundaria
// Número de compilación
// Revisión
//
// Puede especificar todos los valores o usar los valores predeterminados de número de compilación y de revisión
// mediante el carácter '*', como se muestra a continuación:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
-63
View File
@@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Este código fue generado por una herramienta.
// Versión de runtime:4.0.30319.42000
//
// Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
// se vuelve a generar el código.
// </auto-generated>
//------------------------------------------------------------------------------
namespace r2warsTorneo.Properties {
using System;
/// <summary>
/// Clase de recurso fuertemente tipado, para buscar cadenas traducidas, etc.
/// </summary>
// StronglyTypedResourceBuilder generó automáticamente esta clase
// a través de una herramienta como ResGen o Visual Studio.
// Para agregar o quitar un miembro, edite el archivo .ResX y, a continuación, vuelva a ejecutar ResGen
// con la opción /str o recompile su proyecto de VS.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Devuelve la instancia de ResourceManager almacenada en caché utilizada por esta clase.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("r2warsTorneo.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Reemplaza la propiedad CurrentUICulture del subproceso actual para todas las
/// búsquedas de recursos mediante esta clase de recurso fuertemente tipado.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
-117
View File
@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-26
View File
@@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Este código fue generado por una herramienta.
// Versión de runtime:4.0.30319.42000
//
// Los cambios en este archivo podrían causar un comportamiento incorrecto y se perderán si
// se vuelve a generar el código.
// </auto-generated>
//------------------------------------------------------------------------------
namespace r2warsTorneo.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
-7
View File
@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
+176 -24
View File
@@ -1,40 +1,192 @@
# r2wars
C# implementation for r2wars tournament
![r2wars logo](csharp/resources/r2wars_logo_transparent.png?raw=true "r2wars")
Tournament api from: https://github.com/otac0n/tournaments
r2wars is a Core War-style tournament powered by radare2 and ESIL. Two
assembly warriors share a 1 KiB arena and take turns executing instructions.
Each warrior tries to corrupt its opponent until the opponent crashes, traps,
or leaves the arena.
## Description
Warriors may target different CPU architectures while competing in the same
address space.
r2wars is a game similar to corewars, where 2 programs run on a
shared memory space trying to catch each other in order to trash
their code and make them crash.
## Choose how to run it
This game was initially developed by pancake as a PoC in here
| Mode | Requirements | Execution | Best for |
| --- | --- | --- | --- |
| Docker | Docker with Compose | .NET and native radare2 in containers | Fastest local setup |
| Native | .NET 10 and radare2 | Local .NET server and native radare2 | Development and full architecture support |
| WebAssembly | Node.js/npm for building | Entirely inside the browser | Static hosting and serverless deployment |
* https://github.com/radare/radare2-extras/tree/master/r2wars
The WebAssembly implementation is an alternative execution path. It does not
replace or change the existing .NET and Docker flows.
You can find an explanation of the game in the first competition
that happened during the 2nd r2con in 2017.
## Quick start with Docker
* https://www.youtube.com/watch?v=sB-i5yUatx4
From the repository root:
This repository contains an evolved implementation of the engine
written in C# by SkUaTeR dropping the MFC requirement that was
making it impossible to run outside Windows.
```sh
make start
```
The solution was to use an embedded webserver that provides a
web interface using websockets to stream the process changes
from the M
Open <http://127.0.0.1:9664/>. The local `warriors/` directory is mounted
read-only into the container.
## Dependencies
Useful commands:
* Mono / .NET Runtime
* radare2
```sh
make build # build the Docker image
make start # start r2wars and its nginx frontend
make stop # stop the containers
make clean # stop and remove the r2wars image
```
On windows you need to have radare2.exe and rasm2.exe in the same
directory as the r2wars.exe executable.
The Docker image pins radare2 6.2.0 and verifies the official `amd64` or
`arm64` release package before installing it.
On Mac/Linux/BSD, r2wars will try to find them in the PATH.
## Run natively
--pancake
Install the .NET 10 SDK and radare2, then run:
```sh
dotnet run --project csharp/r2wars.csproj -- ../warriors
```
Open <http://127.0.0.1:9664/>.
On Linux, macOS, and BSD, `radare2` and `rasm2` are loaded from `PATH`. On
Windows, put `radare2.exe` and `rasm2.exe` in `PATH` or alongside the published
r2wars application. The native interface uses the same bot manager and editor
as the WebAssembly build; live previews are assembled by native `rasm2`.
## WebAssembly version
The browser version runs the tournament controller and radare2 ESIL locally in
a Web Worker. It has no Kestrel or WebSocket connection, does not require
Docker or .NET at runtime, and never uploads warrior source or tournament state.
### Build and run locally
```sh
make wasm-build
make wasm-run
```
Then open <http://127.0.0.1:5173/>. The production site is generated in
`wasm/dist/`.
The first build downloads the official radare2 6.2.0 WASI API module and
verifies the checksums of both the release archive and extracted Wasm module.
The module is about 44 MB before HTTP or ZIP compression.
### Create a deployable ZIP
```sh
make wasm-dist
```
This creates `wasm/r2wars-wasm.zip`. The archive contains the complete static
site with `index.html` at its root:
```text
index.html
radare2.wasm
assets/
warriors/
```
Extract those files directly into a static server's document root. No
application backend, .NET runtime, radare2 installation, or WebSocket proxy is
needed. The paths are relative, so the site can also be hosted below a URL
prefix.
The server should deliver `.wasm` files as `application/wasm`. Opening
`index.html` through `file://` is not supported because browsers restrict local
Wasm and module loading; use any ordinary HTTP(S) static server instead.
You can choose a different archive name when needed:
```sh
make wasm-dist WASM_ARCHIVE=my-r2wars-build.zip
```
### Shared web controls
- The WebAssembly build initially loads three bundled bots. The .NET build
loads the configured warriors directory.
- Open **Bots** while the tournament is not running to inspect the complete
roster, create or import bots, rename them, edit their assembly, or remove
them.
- Bot edits are drafts. They do not modify a running or paused tournament and
are validated and loaded only when **Start new tournament** is selected.
- Every filename or source edit is assembled immediately by the selected
engine—radare2 Wasm in the static build or native `rasm2` in the .NET build.
The editor shows a red or green result, the compiled size, and the complete
byte array; results over the 512-byte warrior limit are marked red.
- Select **Choose warriors** to replace the draft roster with local `.asm`
files. Dropping `.asm` files onto the page adds or updates bots by filename.
- Tournaments support run, pause, single-cycle stepping, bounded history,
standings, and downloadable reports.
- In the WebAssembly build, tournament execution stays in a worker so the
interface remains responsive.
### Browser architecture support
The official radare2 6.2.0 WASI module contains x86, ARM, MIPS, RISC-V, and
Game Boy support. It does not contain the 8051 plugin, so 8051 warriors require
the native or Docker version for now.
See [wasm/README.md](wasm/README.md) for implementation details and direct npm
commands.
## Writing warriors
A tournament requires at least two non-empty `.asm` files. The architecture
and bitness are encoded before the `.asm` extension:
```text
scanner.x86-32.asm
hammer.arm-64.asm
probe.mips-32.asm
```
Supported filename markers are:
- `.x86-32.asm` and `.x86-64.asm`
- `.arm-16.asm`, `.arm-32.asm`, and `.arm-64.asm`
- `.mips-32.asm` and `.mips-64.asm`
- `.riscv-32.asm` and `.riscv-64.asm`
- `.gb.asm`
- `.8051.asm` in the native and Docker versions
Examples for several architectures are available in `examples/`. The default
native and Docker tournament reads warriors from `warriors/`.
## WebAssembly development commands
Run these from the repository root:
```sh
make wasm-test # test parsers and the engine against the real radare2 Wasm
make wasm-build # type-check and build wasm/dist/
make wasm-run # start the Vite development server
make wasm-dist # build and package wasm/r2wars-wasm.zip
```
The dedicated WebAssembly CI workflow runs the tests and production build, then
uploads `wasm/dist/` as the `r2wars-wasm` artifact.
## Background
The original proof of concept lives in
[radare2-extras](https://github.com/radare/radare2-extras/tree/master/r2wars).
This repository evolved the engine into a portable C# implementation by
SkUaTeR, replacing the original Windows-only MFC interface with a web UI.
Further introductions:
- [r2wars for N00bs — r2con 2020](https://www.youtube.com/watch?v=PB0AFBqFwGQ)
- [r2wars competition — r2con 2017](https://www.youtube.com/watch?v=sB-i5yUatx4)
- [Tournament library](https://github.com/otac0n/tournaments)
— pancake
+2 -2
View File
@@ -12,8 +12,8 @@ supporting other architectures with ESIL as emulation engine.
Introduction
------------
In order to start the competition you need to run r2wars.exe
which is written in C# and runs on Mono, .NET/Core or MSCLR.
In order to start the competition you need the ASP.NET Core Runtime 10,
then run `dotnet r2wars.dll [warriors-directory]`.
The UI has been rewritten from the original MFC to be in HTML,
so the program will run a local webserver which serves a
-358
View File
@@ -1,358 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace r2warsTorneo
{
public class Torneo
{
string warriorsDirectory = "warriors";
static List<TournamentTeam> teams = new List<TournamentTeam>();
static List<TournamentRound> rounds = new List<TournamentRound>();
static Dictionary<long, string> teamNames = new Dictionary<long, string>();
static Dictionary<long, string> teamWarriors = new Dictionary<long, string>();
static r2wars r2w = null;
RoundRobinPairingsGenerator generator;
List<TournamentPairing> allcombats = new List<TournamentPairing>();
TournamentTeamScore[] actualcombatscore = { null, null };
int ncombat = 0;
string[] actualcombatnames = { "", "" };
string[] actualcombatwarriors = { "", "" };
public string fullCombatLog ="";
public string stats ="";
public string actualCombatLog = "";
public bool bTournamentRun = false;
private clsEngine.eArch tournamenArch = clsEngine.eArch.x86;
Task tournamentTask = null;
bool bTournamenTask = false;
bool bCombatEnd = true;
public Torneo()
{
r2w = r2warsStatic.r2w;
}
public void SetWarriorsDirectory(string wd) {
this.warriorsDirectory = wd;
}
private void espera(int veces, int pausa = 1)
{
Task t = Task.Factory.StartNew(() =>
{
int n = veces;
while ((n--) > 0)
{
System.Threading.Thread.Sleep(pausa);
}
});
t.Wait();
}
void drawstats()
{
stats= string.Format("Combat {0} / {1}", ncombat ,allcombats.Count) + Environment.NewLine;
var standings = generator.GenerateRankings();
foreach (var standing in standings)
{
string salida = string.Format("{0} {1} {2}", standing.Rank.ToString(), teamNames[standing.Team.TeamId], standing.ScoreDescription);
stats+= salida + Environment.NewLine;
}
r2w.send_draw_event(r2w.json_output());
r2w.send_draw_event("on");
}
private void RoundEnd(object sender, MyEvent e)
{
int nround = e.round + 1;
fullCombatLog += " Round-" + nround.ToString() + " " + r2w.Engine.players[e.ganador].name + " Wins Cycles:" + e.ciclos.ToString() + Environment.NewLine;
actualCombatLog += " Round-" + nround.ToString() + " " + r2w.Engine.players[e.ganador].name + " Wins Cycles:" + e.ciclos.ToString() + Environment.NewLine;
if (actualcombatscore[e.ganador].Score!=null)
actualcombatscore[e.ganador].Score+= new HighestPointsScore(1);
r2w.send_draw_event(r2w.json_output());
/*Task t = Task.Factory.StartNew(() =>
{
int n = 10;
while ((n--) > 0)
{
System.Threading.Thread.Sleep(100);
Console.WriteLine("Round end Waiting ...");
}
});
t.Wait();*/
}
private void RoundExhausted(object sender, MyEvent e)
{
int nround = e.round + 1;
actualCombatLog += " Round-" + nround.ToString() + " TIMEOUT Cycles:" + e.ciclos.ToString() + Environment.NewLine;
fullCombatLog += " Round-" + nround.ToString() + " TIMEOUT Cycles:" + e.ciclos.ToString() + Environment.NewLine;
}
private void CombatEnd(object sender, MyEvent e)
{
string ganador = "";
if (r2w.victorias[0] == 2)
ganador = r2w.Engine.players[0].name;
if (r2w.victorias[1] == 2)
ganador = r2w.Engine.players[1].name;
int ciclos = r2w.totalciclos;
actualCombatLog += "Combat Winner: " + ganador + Environment.NewLine;
fullCombatLog += "Combat Winner: " + ganador + Environment.NewLine;
ncombat++;
drawstats();
espera(1000);
r2w.send_draw_event("off");
bCombatEnd = true;
}
void runnextcombat(bool startcombat)
{
if (ncombat < allcombats.Count)
{
int j = 0;
foreach (var teamScore in allcombats[ncombat].TeamScores)
{
actualcombatnames[j] = teamNames[teamScore.Team.TeamId];
actualcombatwarriors[j] = teamWarriors[teamScore.Team.TeamId];
actualcombatscore[j] = teamScore;
actualcombatscore[j].Score += new HighestPointsScore(0);
j++;
}
string tmp = string.Format("Iniciando combate {0} {1} vs {2}", ncombat + 1, actualcombatnames[0], actualcombatnames[1]);
actualCombatLog = tmp + Environment.NewLine;
fullCombatLog += tmp + Environment.NewLine;
bCombatEnd = false;
r2w.playcombat(actualcombatwarriors[0], actualcombatwarriors[1], actualcombatnames[0], actualcombatnames[1], startcombat, false, tournamenArch);
}
else
{
fullCombatLog += "Tournament end " + DateTime.Now + Environment.NewLine;
bTournamentRun = false;
r2w.send_draw_event(r2w.json_output());
}
}
public void StopTournament()
{
while (bTournamenTask == true)
{
bTournamentRun = false;
bCombatEnd = true;
Thread.Sleep(100);
}
}
private void dopairs(string[] selectedfiles, string strarch, string extension)
{
generator = new RoundRobinPairingsGenerator();
generator.Reset();
int n = 0;
foreach (string s in selectedfiles)
{
var team = new TournamentTeam(n, 0);
teams.Add(team);
string tmp = Path.GetFileName(selectedfiles[n]);
teamNames.Add(n, tmp.Substring(0, tmp.IndexOf(extension)));
teamWarriors.Add(n, selectedfiles[n]);
n++;
}
// generamos todas las rondas.
while (true)
{
TournamentRound round = null;
generator.Reset();
generator.LoadState(teams, rounds);
round = generator.CreateNextRound(null);
if (round != null)
{
rounds.Add(round);
}
else
{
break;
}
}
foreach (TournamentRound round in rounds)
{
foreach (var pairing in round.Pairings)
{
allcombats.Add(pairing);
}
}
string memoria = "";
for (int x = 0; x < 1024; x++)
memoria += "\"\"" + ",";
memoria = memoria.Remove(memoria.Length - 1);
string salida = "";
salida = "Tournament arch: " + strarch + "\nTotal Warriors loaded " + selectedfiles.Count().ToString() +"\nPress 'start' button to begin tournament." ;
string envio = "{\"player1\":{\"regs\":\"\",\"code\":\"\",\"name\":\"Player - 1\"},\"player2\":{\"regs\":\"\",\"code\":\"\",\"name\":\"Player - 2\"},\"memory\":[" + memoria + "],\"console\":\"" + salida + "\",\"status\":\"Warriors Loaded.\",\"scores\":\"\"}";
r2w.send_draw_event(envio.Replace("\n", "\\n").Replace("\r", ""));
r2w.totalciclos = 0;
}
public void LoadTournamentPlayers()
{
StopTournament();
r2w.StopCombate();
if (bTournamentRun == false)
{
allcombats.Clear();
teamNames.Clear();
teamWarriors.Clear();
rounds.Clear();
teams.Clear();
ncombat = 0;
if (r2w != null)
{
r2w.Event_combatEnd -= new MyHandler1(CombatEnd);
r2w.Event_combatEnd += new MyHandler1(CombatEnd);
r2w.Event_roundEnd -= new MyHandler1(RoundEnd);
r2w.Event_roundEnd += new MyHandler1(RoundEnd);
r2w.Event_roundExhausted -= new MyHandler1(RoundExhausted);
r2w.Event_roundExhausted += new MyHandler1(RoundExhausted);
}
r2w.nRound = 0;
r2w.victorias[0] = 0;
r2w.victorias[1] = 0;
r2w.bDead = false;
fullCombatLog = "";
string[] files = Directory.GetFiles(warriorsDirectory);
string[] selectedfiles = null;
string extension = "";
string[] arm32 = files.Where(p => p.EndsWith(".arm-32.asm")).ToArray();
string[] x8632 = files.Where(p => p.EndsWith(".x86-32.asm")).ToArray();
string[] mips64 = files.Where(p => p.EndsWith(".mips-64.asm")).ToArray();
string strarch = "";
int n = 0;
if (arm32.Count() > 0 && x8632.Count() > 0)
{
Console.Write("Detected mixed archs.\nWhat do you want to run:\n 1) arm 32 bit\n 2) x86 32 bit\n\n 0) exit\n\nSelect option:");
r2w.answer = "";
r2w.send_draw_event("askarch");
Task t = Task.Factory.StartNew(() =>
{
while (r2w.answer == "")
Thread.Sleep(10);
if (r2w.answer == "arm")
{
selectedfiles = arm32;
extension = ".arm-32.asm";
tournamenArch = clsEngine.eArch.arm32;
strarch = "arm 32 bits.";
}
else if (r2w.answer == "x86")
{
selectedfiles = x8632;
extension = ".x86-32.asm";
tournamenArch = clsEngine.eArch.x86;
strarch = "x86 32 bits.";
}
else
return;
dopairs(selectedfiles, strarch, extension);
});
return;
}
else if (mips64.Count() > 0)
{
selectedfiles = arm32;
extension = ".mips-64.asm";
tournamenArch = clsEngine.eArch.mips64;
strarch = "mips 64 bits.";
}
else if (arm32.Count() > 0)
{
selectedfiles = arm32;
extension = ".arm-32.asm";
tournamenArch = clsEngine.eArch.arm32;
strarch = "arm 32 bits.";
}
else if (x8632.Count() > 0)
{
selectedfiles = x8632;
extension = ".x86-32.asm";
tournamenArch = clsEngine.eArch.x86;
strarch = "x86 32 bits.";
}
else
{
Console.WriteLine("Warriors dont found. plz copy inside this folder '.x86-32' or '.arm-32' warriors.");
return;
}
dopairs(selectedfiles, strarch, extension);
}
}
public void StopActualCombat()
{
r2w.StopCombate();
}
public void StepTournamentCombats()
{
if (bTournamentRun == false)
{
RunTournamentCombats(false);
r2w.bInCombat = true;
}
else if (r2w.bThreadIni == false)
{
r2w.stepCombate();
}
}
public void RunTournamentCombats(bool startcombat)
{
if (bTournamentRun == false)
{
fullCombatLog = "Tournament start " + DateTime.Now + Environment.NewLine;
bTournamentRun = true;
tournamentTask = Task.Factory.StartNew(() =>
{
bool firsttime = true;
bTournamenTask = true;
System.Diagnostics.Debug.WriteLine("TournamenTask: Ini.");
while (bTournamentRun)
{
if (bCombatEnd == true)
{
if (firsttime && !startcombat)
runnextcombat(false);
else
runnextcombat(true);
}
else
Thread.Sleep(100);
}
bTournamenTask = false;
System.Diagnostics.Debug.WriteLine("TournamenTask: Fin.");
});
}
else
r2w.iniciaCombate();
}
}
}
-516
View File
@@ -1,516 +0,0 @@
<html>
<script>
var clicked = false;
var clicked1 = false;
document.addEventListener('DOMContentLoaded', function () {
$('reset').addEventListener('click', () => {
socket.send("reset_tournament");
document.getElementById("start").innerHTML = "start";
clicked = false;
});
$('start').addEventListener('click', () => {
if (clicked === false) {
socket.send("start_tournament");
document.getElementById("start").innerHTML ="pause";
clicked = true;
}
else if (clicked === true) {
document.getElementById("start").innerHTML ="continue";
socket.send("stop_tournament");
clicked = false;
}
});
$('next').addEventListener('click', () => {
socket.send("next");
});
$('buffer').addEventListener('click', () => {
on();
});
$('lt').addEventListener('click', () => {
socket.send("prevlog");
});
$('gt').addEventListener('click', () => {
socket.send("nextlog");
});
$('x86').addEventListener('click', () => {
hideArchDlg();
socket.send("arch_x86")
});
$('arm').addEventListener('click', () => {
hideArchDlg();
socket.send("arch_arm")
});
updateUI();
});
var state = {};
resetState();
var socket = new WebSocket('ws://localhost:9966/r2wars');
socket.onopen = function ()
{
};
socket.onclose = function ()
{
};
socket.onmessage = function (evt) {
//alert(evt.data);
if (evt.data !== "none") {
if (evt.data == "on") {
on();
}
else if (evt.data == "off") {
off();
}
else if (evt.data == "askarch") {
showArchDlg();
}
else {
state = JSON.parse(evt.data);
updateUI();
//socket.send("moreflow");
}
}
};
function resetState() {
state = {
player1: {
regs: '',
code: '',
name: 'Player - 1',
},
player2: {
regs: '',
code: '',
name: 'Player - 2',
},
memory: [
'',
'',
'',
'',
],
console: '[r2wars]',
status: 'idle',
scores: ''
};
}
function updateUI() {
var memory = memoryWidget();
$('memory').innerHTML = memory;
$('status').innerHTML = state.status;
$('console').innerHTML = state.console;
$('regs1').innerHTML = state.player1.regs;
$('code1').innerHTML = state.player1.code;
$('regs2').innerHTML = state.player2.regs;
$('code2').innerHTML = state.player2.code;
$('player1').innerHTML = state.player1.name;
$('player2').innerHTML = state.player2.name;
$('scores').innerHTML = state.scores;
}
function addrForRow(x) {
return "0x" + ("0000" + x.toString(16)).substr(-4);
}
function styler(x) {
var color='white';
switch(x) {
case 'r': color='red'; break;
case 'y': color='yellow'; break;
case 'g': color='green'; break;
case 'w': color='white'; break;
case 'n': color='black'; break;
case 'b': color='blue'; break;
case 'q': color='aqua'; break;
case 'o': color='orange'; break;
case 'v': color='violet'; break;
}
return 'background-color:'+ color;
}
function memoryWidget() {
var a = '<table class="memtable">';
var rows = 32;
var rowlen = 32;
for (i = 0; i<rows; i++) {
var addr = addrForRow(i * rowlen);
var row = "";
for (j = 0; j <rowlen;j++) {
var s = state.memory[(i * rowlen) + j];
var ch = ((s&&s.length) > 1)? s[1]: '&nbsp;';
var style = (s&&s.length > 0)? styler(s[0]): '';
row += '<td style="'+style+'" class="box">'+ch+'</td>'
}
a += "<tr><td class='addr'>"+addr+"</td>"+row+"</tr>";
}
return a + '</table>';
}
function $(x) {
return document.getElementById(x);
}
function Query(c, cb) {
Ajax('GET', '/r2wars/' + encodeURI(c), '', function(x) { if (cb) { cb(x); } });
}
var ajax_in_process = false;
function Ajax(method, uri, body, fn) {
if (typeof (XMLHttpRequest) == 'undefined') {
return false;
}
console.log('async waiting');
if (ajax_in_process) {
setTimeout(function() {
Ajax(method, uri, body, fn);
}, 100);
return false;
}
var x = new XMLHttpRequest();
if (!x) {
return false;
}
ajax_in_process = true;
x.open(method, uri, false);
x.setRequestHeader('Accept', 'text/plain');
x.setRequestHeader ('Accept', 'text/html');
x.onreadystatechange = function() {
ajax_in_process = false;
if (x.status == 200) {
if (fn) {
fn(x.responseText);
} else {
console.error('missing ajax callback');
}
} else {
console.error('ajax ' + x.status);
}
};
x.send(null);
}
function on() {
document.getElementById("overlay").style.display = "block";
}
function off() {
document.getElementById("overlay").style.display = "none";
}
function showArchDlg() {
document.getElementById("askarchdlg").style.display = "block";
}
function hideArchDlg() {
document.getElementById("askarchdlg").style.display = "none";
}
display: none;
</script>
<style>
table {
}
button {
width:100%;
}
.addr {
color:white;
background-color:black;
}
.memory {
overflow-y: scroll;
height:100%;
}
.box {
width:1em;
height:1em;
color: white;
background-color:#a0a0a0;
}
.console {
height: 200px;
background-color:black;
color:white;
font-family: Courier New;
font-weight:bold;
white-space: pre;
overflow-y: scroll;
}
.console1 {
height: 200px;
background-color:black;
color:white;
font-family: Courier New;
font-weight:bold;
white-space: pre;
}
.console2 {
height: 400px;
background-color:black;
color:green;
font-family: Courier New;
font-weight:bold;
white-space: pre;
}
.s {
background-color:green;
color:black;
font-family: Courier New;
font-weight:bold;
white-space: pre;
}
body {
background-color:#c0c0c0;
}
td {
font-family: Courier New;
border: 1px solid #a0a0a0;
}
div {
font-family: Courier New;
}
tr {
background-color:#e0e0e0;
}
.player1 {
background-color:blue;
color:white;
font-weight:bold;
font-size:2em;
font-family: Courier New;
text-align:center;
}
.player2 {
color:white;
background-color:red;
font-weight:bold;
font-size:2em;
font-family: Courier New;
text-align:center;
}
.memtable {
font-size: 10px;
}
.overlay {
display: none;
top: 1%;
left: 30%;
right: 30%;
bottom: 27%;
background-color:rgba(0, 0, 0, 0.9);
z-index: 2;
cursor: pointer;
position: absolute;
border-radius: 6px;
border: 1px solid #a0a0a0
}
.text{
position: absolute;
top: 4%;
left: 50%;
font-size: 40px;
color: green;
transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
}
.text1{
position: absolute;
top: 14%;
left: 50%;
font-size: 20px;
color: green;
transform: translate(-50%,0%);
-ms-transform: translate(-50%,0%);
white-space: pre;
}
.win98{
display: none;
top: 30%;
left: 30%;
right: 30%;
z-index: 3;
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: none;
font-size: 11px;
font-family: Tahoma, Verdana;
color: #070707;
position: absolute;
margin: 0 auto;
background: #bfbfbf;
border: 1px solid;
border-top-color: #dfdfdf;
border-left-color: #dfdfdf;
border-right-color: #808080;
border-bottom-color: #808080;
box-shadow: 1px 1px 0 0 #000;
width: 400px;
cursor: default;
}
.win98 .content {
padding: 7px 10px;
font-size: 16px;
}
.win98 .header {
margin: 2px 2px 0;
padding: 1px 2px;
color: #fff;
background: -webkit-linear-gradient(left, blue, red);
background: linear-gradient(to right, blue, red);
font-weight: bold;
font-size: 16px;
line-height: 16px;
}
.win98 button {
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: none;
font-size: 11px;
font-family: Tahoma, Verdana;
color: #070707;
background: #bfbfbf;
border: 1px solid;
border-top-color: #dfdfdf;
border-left-color: #dfdfdf;
border-right-color: #808080;
border-bottom-color: #808080;
box-shadow: 1px 1px 0 0 #000;
text-align: center;
outline: none;
padding: 4px;
cursor: default;
font-size: 16px;
}
.win98 button:enabled {
color: #070707;
}
.win98 button:disabled {
color: #818181;
text-shadow: 1px 1px #fff;
}
.win98 button:active:enabled {
box-shadow: 1px 1px 0 0 #000 inset;
border-top-color: #808080;
border-left-color: #808080;
border-right-color: #dfdfdf;
border-bottom-color: #dfdfdf;
}
</style>
<body>
<div id="overlay" class="overlay" onclick="off()">
<div class="text">Score Board</div>
<div id="scores" class="text1"></div>
</div>
<div id="askarchdlg" class='win98'>
<div class='header'>
Multiple warriors detected:
</div>
<div class='content'>
<center>
<h3>What Arch do you want to run?</h3>
<table style="width:100%">
<tr>
<td><button id="arm">ARM 32 bits</button></td>
<td><button id="x86">X86 32 bits</button></td>
</tr>
</table>
</center>
</div>
</div>
<table style="width:100%;height:100%">
<tr>
<td style="width:30%">
<table style="height:100%;width:100%">
<tr>
<td class="player1" id=player1>Player 1</td>
</tr>
<tr style="height:100%">
<td valign=top>
<div class=console1 id=regs1>regs</div>
<div style="border: 1px solid #a0a0a0"></div>
<div class=console2 id=code1>code</div>
</td>
</tr>
</table>
</td>
<td style="width:30%">
<table style="height:100%;width:100%">
<tr style="height:100%">
<td valign=top><div class=memory id=memory>memory</div></td>
</tr>
<tr style="height:100%">
<td>
<table style="width:100%">
<tr>
<td><button id="reset">Load Warriors</button></td>
<td><button id="start">Start</button></td>
<td><button id="next">Next</button></td>
<td><button id="buffer">Scores</button></td>
<td><button id="lt">&lt;</button></td>
<td><button id="gt">&gt;</button></td>
</tr>
</table>
</td>
</tr>
<tr style="height:100%">
<td><div id="console" class="console">console</div></td>
</tr>
<tr style="height:100%">
<td id="status">status</td>
</tr>
</table>
</td>
<td style="width:30%">
<table style="height:100%;width:100%">
<tr>
<td class="player2" id=player2>Player 2</td>
</tr>
<tr style="height:100%">
<td valign=top height="100%">
<div class=console1 id=regs2>regs</div>
<div style="border: 1px solid #a0a0a0"></div>
<div class=console2 id=code2>code</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
-894
View File
@@ -1,894 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace r2warsTorneo
{
public class clsinfo
{
public string pc = "";
public string ins = "";
public string dasm = "";
public string regs = "";
public string mem = "";
public string txtmemoria = "";
public int cycles = 0;
public bool dead = false;
public clsinfo(string pc, string ins, string dasm, string regs, string mem, int cycles, string txtmemoria)
{
this.pc = pc;
this.ins = ins;
this.dasm = dasm;
this.regs = regs;
this.mem = mem;
this.cycles = cycles;
this.txtmemoria = txtmemoria;
}
public int ipc()
{
if (pc != "")
{
int ipc = Convert.ToInt32(pc.Substring(3), 16);
return ipc;
}
return -1;
}
public string formatregs()
{
string[] reg = regs.Split('\n');
string regformat = "";
int x = 0;
foreach (string s in reg)
{
if (s.StartsWith("oeax") == false)
{
if (x % 3 == 0 && x != 0)
regformat += "\n";
regformat += s + " ";
x++;
}
}
return regformat;
}
}
public class player
{
public string name = "";
public int orig = 0;
public int size = 0;
public string user = "";
public string code = "";
public string userini = "";
public int cycles = 0;
public int cyclesfixed = 0;
public clsinfo actual;
public List<clsinfo> log;
int idxlog;
public player(string name, int orig, int size, string code, string user, int ciclos) //,string dasm,string mem,string ins, string pc, string reg)
{
this.name = name;
this.orig = orig;
this.size = size;
this.user = user;
this.code = code;
this.userini = user;
this.cycles = ciclos;
this.cyclesfixed = ciclos;
this.log = new List<clsinfo>();
this.actual = new clsinfo("", "", "", "", "", 0,"");
idxlog = -1;
}
public void logClear()
{
log.Clear();
idxlog = 0;
}
public void logAdd(clsinfo entry)
{
log.Add(entry);
idxlog = log.Count();
}
public string logGetFull()
{
string res = "";
for (int x = 0; x < log.Count; x++)
{
res += log[x].formatregs() + "\n" + log[x].dasm + "\n";
}
return res;
}
public clsinfo logGetPrev()
{
if (idxlog <0)
{
return null;
}
else if (idxlog > 0)
{
idxlog--;
}
return log[idxlog];
}
public clsinfo logGetNext()
{
if (idxlog < 0 || idxlog>log.Count-1)
{
return null;
}
else if (idxlog < log.Count - 1)
{
idxlog++;
}
return log[idxlog];
}
}
public class clsEngine
{
private string _r2path = "";
private string _rasm2path = "";
public int memsize = 1024;
public int maxprogsize = 64;
private IR2Pipe r2 = null;
private int nPlayers = 0;
public int uidx = 0;
public List<player> players = new List<player>();
public enum eArch
{
mips32,
mips64,
arm16,
arm32,
arm64,
gb,
x86,
x64
}
private eArch _arch = eArch.x86;
public string arch
{
get
{
if (_arch == eArch.arm16)
return "arm 16 bits";
if (_arch == eArch.arm32)
return "arm 32 bits";
if (_arch == eArch.arm64)
return "arm 64 bits";
if (_arch == eArch.mips32)
return "mips 32 bits";
if (_arch == eArch.mips64)
return "mips 64bits";
if (_arch == eArch.gb)
return "gb 16 bits";
if (_arch == eArch.x64)
return "x86 64 bits";
return "x86 32 bits";
}
}
public string r2path
{
get
{
if (_r2path == "")
{
string ruta = "";
if (!OperatingSystem.IsWindows())
ruta = "r2";
else
ruta = "radare2.exe";
return ruta;
}
return this._r2path;
}
set
{
this._r2path = value;
}
}
public string rasm2path
{
get
{
if (_rasm2path == "")
{
string ruta = "";
if (!OperatingSystem.IsWindows())
ruta = "rasm2";
else
ruta = "rasm2.exe";
return ruta;
}
else
return this._rasm2path;
}
set
{
this._rasm2path = value;
}
}
public string runcommand(string cmd)
{
return this.r2.RunCommand(cmd).Replace("\r", "");
}
public string RunAndGetOutput(string program, string arguments)
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = program;
p.StartInfo.Arguments = arguments;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
return output;
}
List<int> get_random_offsets(int nRandoms)
{
System.Random rnd = new System.Random();
List<int> rand = new List<int>();
int addr = rnd.Next(0, this.memsize - this.maxprogsize);
if (addr % 4 != 0)
addr -= addr % 4;
rand.Add(addr);
int ini = addr;
int fin = addr + maxprogsize;
while (true)
{
addr = rnd.Next(0, this.memsize - this.maxprogsize);
if (addr % 4 != 0)
addr -= addr % 4;
if ((addr < ini && addr + maxprogsize < ini) || (addr > fin))
{
rand.Add(addr);
break;
}
}
return rand;
}
string initstate = "";
public string Init(string[] files, string[] usernames, eArch arch)
{
players.Clear();
initstate = "";
Console.WriteLine("r2path = " + r2path);
if (File.Exists(r2path) || !OperatingSystem.IsWindows())
{
List<int> offsets;
int idx = 0;
string file = "";
string strname = "";
string cone = string.Format("-w malloc://{0}", this.memsize);
if (this.r2 == null)
this.r2 = new R2Pipe(cone, r2path);
// el primer comando enviado no parece funcionar luego todo va bien.
this.r2.RunCommand("pd");
//
string rasm2param = "";
if (arch == eArch.mips32)
{
_arch = eArch.mips32;
this.r2.RunCommand("e asm.arch=mips");
this.r2.RunCommand("e asm.bits=32");
rasm2param = "-a mips -b 32";
}
else if (arch == eArch.mips64)
{
_arch = eArch.mips32;
this.r2.RunCommand("e asm.arch=mips");
this.r2.RunCommand("e asm.bits=64");
rasm2param = "-a mips -b 64";
}
else if (arch == eArch.arm64)
{
_arch = eArch.mips32;
this.r2.RunCommand("e asm.arch=arm");
this.r2.RunCommand("e asm.bits=64");
rasm2param = "-a mips -b 64";
}
else if (arch == eArch.arm32)
{
_arch = eArch.arm32;
this.r2.RunCommand("e asm.arch=arm");
this.r2.RunCommand("e asm.bits=32");
rasm2param = "-a arm -b 32";
}
else if (arch == eArch.arm16)
{
_arch = eArch.arm16;
this.r2.RunCommand("e asm.arch=arm");
this.r2.RunCommand("e asm.bits=16");
rasm2param = "-a arm -b 16";
}
else if (arch == eArch.gb)
{
_arch = eArch.gb;
this.r2.RunCommand("e asm.arch=gb");
this.r2.RunCommand("e asm.bits=16");
rasm2param = "-a gb -b 16";
}
else if (arch == eArch.x64)
{
_arch = eArch.x64;
this.r2.RunCommand("e asm.arch=x86");
this.r2.RunCommand("e asm.bits=64");
rasm2param = "-a x86 -b 64";
}
else
{
_arch = eArch.x86;
this.r2.RunCommand("e asm.arch=x86");
this.r2.RunCommand("e asm.bits=32");
rasm2param = "-a x86 -b 32";
}
this.r2.RunCommand("e scr.color=false");
this.r2.RunCommand("e asm.lines=false");
this.r2.RunCommand("e asm.flags=false");
this.r2.RunCommand("e asm.comments=false");
this.r2.RunCommand("aei");
if (initstate == "")
{
this.r2.RunCommand("aeim");
initstate = this.r2.RunCommand("aerR").Replace("\r", "").Replace("\n", ";");
}
else
{
this.r2.RunCommand(initstate);
}
this.r2.RunCommand(string.Format("w0 {0} @ 0", memsize));
nPlayers = files.Count();
offsets = get_random_offsets(this.nPlayers);
for (int x = 0; x < this.nPlayers; x++)
{
file = files[x];
int addr = offsets[idx];
idx++;
string src = RunAndGetOutput(rasm2path, string.Format("{0} -f {1}", rasm2param, file)).Replace("\r", "").Replace("\n", "");
if (src == "")
{
return "Invalid source";
}
Console.WriteLine("Rasm Output = " + src);
// Añadimos el codigo a radare2
string cmd = string.Format("wx {0} @ {1}", src, addr);
this.r2.RunCommand(cmd);
cmd = string.Format("aer PC={0}", addr);
this.r2.RunCommand(cmd);
cmd = string.Format("aer SP=SP+{0}", addr);
this.r2.RunCommand(cmd);
string initRegs = this.r2.RunCommand("aerR").Replace("\r", "").Replace("\n", ";");
// generamos el jugador
strname = usernames[x];
int ciclos = GetPCInstructionCycles(x);
// Iniciamos el jugador añadiendo sus datos de programa, ciclos
player p = new player(strname, addr, src.Length / 2, src, initRegs, ciclos);
// lo añadimos a la lista de jugadores
players.Add(p);
players[x].actual.ins = GetPCInstruction(x);
players[x].actual.dasm = GetFullProgram(x);
players[x].actual.regs = GetRegs(x);
players[x].actual.pc = "0x" + GetPC(x).ToString("X8");
players[x].actual.mem = GetMemAccessRAW(x);
// borramos el log
p.log.Clear();
}
if (players.Count < 2)
{
return "You need at least 2 users";
}
this.r2.RunCommand("e cmd.esil.todo=f theend=1");
this.r2.RunCommand("e cmd.esil.trap=f theend=1");
this.r2.RunCommand("e cmd.esil.intr=f theend=1");
this.r2.RunCommand("e cmd.esil.ioer=f theend=1");
this.r2.RunCommand("f theend=0");
this.r2.RunCommand(string.Format("b {0}", memsize));
return "OK";
}
return "NOK";
}
public bool ReiniciaGame(bool bNew)
{
List<int> offsets = get_random_offsets(this.nPlayers);
string cmd = "";
this.r2.RunCommand(string.Format("w0 {0} @ 0", memsize));
for (int x = 0; x < this.nPlayers; x++)
{
this.r2.RunCommand(players[x].userini);
players[x].user = players[x].userini;
if (bNew)
{
// ponemos la nueva direccion
players[x].orig = offsets[x];
// restauramos el contexto inicial
this.r2.RunCommand(players[x].user);
// ponemos el nuevo PC
cmd = string.Format("aer PC={0}", offsets[x]);
this.r2.RunCommand(cmd);
// obtenemos los registros
string initRegs = this.r2.RunCommand("aerR").Replace("\r", "").Replace("\n", ";");
// actualizamos los registros iniciales del usuario
players[x].user = initRegs;
players[x].userini = initRegs;
}
else
{
// restauramos el contexto inicial
this.r2.RunCommand(players[x].user);
}
cmd = string.Format("wx {0} @ {1}", players[x].code, players[x].orig);
this.r2.RunCommand(cmd);
// Actualizamos la informacion del PC actual
players[x].actual.ins = GetPCInstruction();
players[x].actual.dasm = GetFullProgram();
players[x].actual.regs = GetRegs();
players[x].actual.pc = "0x" + GetPC().ToString("X8");
players[x].actual.mem = GetMemAccessRAW();
// borramos el log
players[x].log.Clear();
}
this.r2.RunCommand("f theend=0");
return true;
}
public bool checkDead()
{
string te = this.r2.RunCommand("?v 1+theend").Replace("\r", "").Replace("\n", "");
if (te != "" && te != "0x1")
{
return true;
}
return false;
}
public void switchUser()
{
uidx++;
if (uidx >= players.Count)
uidx = 0;
this.r2.RunCommand(players[this.uidx].user);
}
public void switchUser(int nuser)
{
if (nuser >= 0 && nuser < players.Count)
{
this.r2.RunCommand(players[nuser].user);
uidx = nuser;
}
}
public int thisplayer
{
get
{
return this.uidx;
}
}
public int otherplayer
{
get
{
int o = this.uidx + 1;
if (o >= players.Count)
o = 0;
return o;
}
}
public void switchUserIdx()
{
uidx++;
if (uidx >= players.Count)
uidx = 0;
}
public void switchUserIdx(int nuser)
{
if (nuser >= 0 && nuser < players.Count)
{
uidx = nuser;
}
}
public bool cyleszero()
{
if (players[this.uidx].cycles == 0)
{
players[this.uidx].cycles = -1;
return true;
}
players[this.uidx].cycles--;
return false;
}
public int stepIn()
{
this.r2.RunCommand("aes");
players[this.uidx].user = this.r2.RunCommand("aerR").Replace("\r", "").Replace("\n", ";");
players[this.uidx].cycles = GetPCInstructionCycles();
return GetPC(this.uidx);
}
public void stepIn(int nuser)
{
switchUser(nuser);
stepIn();
}
public int GetPC()
{
string tmp = this.r2.RunCommand("aer PC");
string tmp1 = tmp.Substring(3).Replace("\r", "").Replace("\n", "");
int res = Convert.ToInt32(tmp1, 16);
return res;
}
public int GetPC(int nuser)
{
switchUser(nuser);
return GetPC();
}
public string GetPCInstruction()
{
string a = this.r2.RunCommand("o");
string b = this.r2.RunCommand("s PC;pd 1").Replace("\r", "");
return b.Replace("\n","");
}
public string GetPCInstruction(int nuser)
{
switchUser(nuser);
return GetPCInstruction();
}
public int GetPCInstructionCycles(int nuser)
{
switchUser(nuser);
return GetPCInstructionCycles();
}
public int GetPCInstructionCycles()
{
int result = 0;
string json = this.r2.RunCommand("s PC; aoj 1").Replace("\r", "");
int ini = json.IndexOf("cycles");
if (ini > 0)
{
string tmp = json.Substring(ini + 8, json.IndexOf(",", ini + 8) - (ini + 8));
int.TryParse(tmp, out result);
if (result < 0) result = 0;
}
return result;
}
public string GetRegs(string format = "")
{
return this.r2.RunCommand("aer" + format).Replace("\r", "");
}
public string GetRegs(int nuser)
{
switchUser(nuser);
return GetRegs();
}
public string GetPCProgram()
{
string query = string.Format("s PC; pd 8");
string tmp = this.r2.RunCommand(query);
return tmp.Replace("\r", "");
}
public string GetPCProgram(int nuser)
{
switchUser(nuser);
return GetPCProgram();
}
public string GetFullProgram()
{
string query = string.Format("pD {0} @ {1}", players[this.uidx].size, players[this.uidx].orig);
string tmp = this.r2.RunCommand(query);
return tmp.Replace("\r", "");
}
public string GetFullProgram(int nuser)
{
switchUser(nuser);
return GetFullProgram();
}
public string GetMemAccessRAW()
{
return this.r2.RunCommand("s PC;aea*").Replace("\r", "");
}
public string GetMemAccessRAW(int nuser)
{
switchUser(nuser);
return GetMemAccessRAW();
}
public Dictionary<int, int> GetMemAccessReadDict(string memaccess)
{
string[] ls = memaccess.Split('\n');
int address = 0;
int size = 0;
Dictionary<int, int> dicMemRead = new Dictionary<int, int>();
foreach (string s in ls)
{
if (s.StartsWith("f mem.read."))
{
try
{
string[] l = s.Substring(s.IndexOf("0x")).Replace(" ", "").Split('@');
size = Convert.ToInt32(l[0].Substring(2), 16);
address = Convert.ToInt32(l[1].Substring(2), 16);
dicMemRead.Add(address, size);
}
catch (Exception ex)
{
}
}
}
return dicMemRead;
}
public int GetMemAccessRead(string memaccess)
{
Dictionary<int, int> dicMemRead = GetMemAccessReadDict(memaccess);
if (dicMemRead.Count > 0)
{
foreach (var a in dicMemRead)
{
if (a.Key >= 0 && a.Key <= memsize)
return a.Key;
else
return -1;
}
}
return -1;
}
public int GetMemAccessRead(int nuser, string memaccess)
{
switchUser(nuser);
return GetMemAccessRead(memaccess);
}
public Dictionary<int, int> GetMemAccessWriteDict(string memaccess)
{
string[] ls = memaccess.Split('\n');
int address = 0;
int size = 0;
Dictionary<int, int> dicMemWrite = new Dictionary<int, int>();
foreach (string s in ls)
{
if (s.StartsWith("f mem.write."))
{
try
{
string[] l = s.Substring(s.IndexOf("0x")).Replace(" ", "").Split('@');
size = Convert.ToInt32(l[0].Substring(2), 16);
address = Convert.ToInt32(l[1].Substring(2), 16);
dicMemWrite.Add(address, size);
}
catch (Exception ex)
{
}
}
}
return dicMemWrite;
}
public int GetMemAccessWrite(string memaccess)
{
Dictionary<int, int> dicMemWrite = GetMemAccessWriteDict(memaccess);
if (dicMemWrite.Count > 0)
{
foreach (var a in dicMemWrite)
{
if (a.Key >= 0 && a.Key <= memsize)
return a.Key;
else
return -1;
}
}
return -1;
}
public int GetMemAccessWrite(int nuser, string memaccess)
{
switchUser(nuser);
return GetMemAccessWrite(memaccess);
}
public string GetUserName()
{
return players[uidx].name;
}
public string GetUserName(int nuser)
{
if (players.Count > 0)
return players[nuser].name;
else
return "";
}
public int GetAddressProgram()
{
return players[uidx].orig;
}
public int GetAddressProgram(int nuser)
{
return players[nuser].orig;
}
public int GetSizeProgram()
{
return players[uidx].size;
}
public int GetSizeProgram(int nuser)
{
return players[nuser].size;
}
public int GetCycles()
{
return players[uidx].cycles;
}
public int GetCycles(int nuser)
{
return players[nuser].cycles;
}
public bool stepInfoNew(string txtmemoria)
{
// Obtenemos los indices del jugador actual y el otro
int thisplayer = uidx;
int otherplayer = uidx + 1;
if (otherplayer >= players.Count)
otherplayer = 0;
string res = this.r2.RunCommand(players[thisplayer].user + ";s PC;aea*;aes;aerR;s PC;aoj 1;aer PC;?v 1+theend").Replace("\r", "");
string[] lines = res.Split('\n');
string[] regs = lines.Where(i => i.StartsWith("aer")).ToArray();
string[] memaccess = lines.Where(i => i.StartsWith("f")).ToArray();
string[] json = lines.Where(i => i.StartsWith("[")).ToArray();
string[] PC = lines.Where(i => i.StartsWith("0x")).ToArray();
string userregs = string.Join(";", regs);
string regs1 = string.Join("\n", regs).Replace("aer ", "");
string mem = string.Join("\n", memaccess);
string j = json[0];
int ini = j.IndexOf("cycles");
int ciclos = 0;
if (ini > 0)
{
string tmp = j.Substring(ini + 8, j.IndexOf(",", ini + 8) - (ini + 8));
int.TryParse(tmp, out ciclos);
if (ciclos < 0) ciclos = 0;
}
// Generamos la peticion de desensamblado del PC actual del jugador actual
int pc = Convert.ToInt32(PC[0].Substring(3), 16);
string query = "";
if (pc < players[thisplayer].orig || pc >= players[thisplayer].orig + players[thisplayer].size)
query = string.Format("s PC; pd 8");
else
query = string.Format("pD {0} @ {1}", players[thisplayer].size, players[thisplayer].orig);
int otherpc = players[otherplayer].actual.ipc();
Dictionary<int, int> dicMemWrite = GetMemAccessWriteDict(mem);
bool bThisPCAltered = false;
bool bOtherPCAltered = false;
if (dicMemWrite.Count > 0)
{
foreach (var i in dicMemWrite)
{
if (i.Key >= 0 && i.Key <= memsize)
{
for (int x = 0; x < i.Value; x++)
{
if (i.Key + x == otherpc)
{
bOtherPCAltered = true;
}
if (i.Key + x == pc)
{
bThisPCAltered = true;
}
}
}
}
}
// Generamos la peticion de desensamblado del PC del otro jugador
string otherquery = "";
if (otherpc < players[otherplayer].orig || otherpc >= players[otherplayer].orig + players[otherplayer].size)
otherquery = string.Format("s {0}; pd 8", players[otherplayer].actual.pc);
else
otherquery = string.Format("pD {0} @ {1}", players[otherplayer].size, players[otherplayer].orig);
// Procesamos el output de radare y obtenemos los 2 desensamblados
string bothdasm = this.r2.RunCommand(query + ";?e split;" + otherquery).Replace("\r", "");
string[] tmpdasm = bothdasm.Split(new string[] { "split" }, StringSplitOptions.None);
string dasm = tmpdasm[0];
string otherdasm = tmpdasm[1];
int x1 = dasm.IndexOf(PC[0]);
string newins = dasm.Substring(x1, dasm.IndexOf('\n', x1) - x1);
if (PC[1] != "" && PC[1] != "0x1")
players[thisplayer].actual.dead = true;
else
players[thisplayer].actual.dead = false;
// si han cambiado los desensamblados del otro jugador, actualizamos y añadimos una linea de log con el nuevo.
if (bOtherPCAltered)
{
players[otherplayer].actual.dasm = otherdasm;
}
//
// si han cambiado los desensamblados del jugador actual, actualizamos y añadimos una linea de log con el nuevo.
if (bThisPCAltered)
{
players[thisplayer].actual.dasm = dasm;
}
// Añadimos al log la instruccion que se ejecuto
players[thisplayer].logAdd(new clsinfo(players[thisplayer].actual.pc, players[thisplayer].actual.ins, players[thisplayer].actual.dasm, players[thisplayer].actual.regs, players[thisplayer].actual.mem, players[thisplayer].cycles+1, txtmemoria));
// Actualizamos los ciclos y registros
players[this.uidx].user = userregs;
if (players[this.uidx].cycles == -1)
players[this.uidx].cyclesfixed = ciclos;
players[this.uidx].cycles = ciclos;
// Actualizamos la instruccion actual
players[thisplayer].actual.pc = PC[0];
players[thisplayer].actual.ins = newins;
players[thisplayer].actual.mem = mem;
players[thisplayer].actual.dasm = dasm;
players[thisplayer].actual.regs = regs1;
return players[thisplayer].actual.dead;
}
public string formatregs(string regs)
{
string[] reg = regs.Split('\n');
string regformat = "";
int x = 0;
foreach (string s in reg)
{
if (s.StartsWith("oeax") == false)
{
if (x % 3 == 0 && x != 0)
regformat += "\n";
regformat += s + " ";
x++;
}
}
return regformat;
}
}
}
+22
View File
@@ -0,0 +1,22 @@
services:
r2wars:
image: r2wars:latest
build: .
volumes:
- ./warriors:/r2wars/warriors:ro
expose:
- 9664
ports:
- 127.0.0.1:9966:9966
init: true
tty: true
container_name: r2wars
web:
image: nginx:alpine
depends_on:
- r2wars
ports:
- 127.0.0.1:9664:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
+28
View File
@@ -0,0 +1,28 @@
VERSION=$(shell ../version.sh)
R2W=r2wars-$(VERSION)
DOTNET?=dotnet
all:
$(DOTNET) build r2wars.sln
run:
$(DOTNET) run --project r2wars.csproj -- ../warriors
ls:
$(SHELL) lsbots.sh
dist:
rm -rf $(R2W)
$(DOTNET) publish r2wars.csproj --configuration Release --output $(R2W) --no-self-contained
cp -f ../RELEASE_README.md $(R2W)/README.txt
mkdir -p $(R2W)/warriors
cp -rf ../examples/. $(R2W)/warriors
zip -r $(R2W).zip $(R2W)
rm -rf $(R2W)
r2w32:
wget -c http://radare.mikelloc.com/get/2.7.0/radare2_installer-msvc_64-2.7.0.exe
clean:
$(DOTNET) clean r2wars.sln
rm -rf bin obj r2wars-*.zip
+5
View File
@@ -4,6 +4,11 @@ public class MyEvent : EventArgs
{
public string message;
public int ganador;
public int perdedor;
public string winnername;
public string losername;
public string loserreason;
public string loserins;
public int round;
public int ciclos;
}
+75
View File
@@ -0,0 +1,75 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Net.WebSockets;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace r2warsTorneo
{
static public class r2warsStatic
{
static public r2wars r2w = new r2wars();
static public Torneo torneo = new Torneo();
}
class Program
{
static async Task Main(string[] args)
{
string listenAddress = OperatingSystem.IsWindows() ? "127.0.0.1" : "0.0.0.0";
string httpUrl = Environment.GetEnvironmentVariable("R2WARS_HTTP_URL") ??
"http://" + listenAddress + ":9664";
string websocketUrl = Environment.GetEnvironmentVariable("R2WARS_WEBSOCKET_URL") ??
"http://" + listenAddress + ":9966";
if (args.Length > 0)
r2warsStatic.torneo.SetWarriorsDirectory(args[0]);
WebApplicationBuilder builder = WebApplication.CreateEmptyBuilder(new WebApplicationOptions
{
ContentRootPath = AppContext.BaseDirectory,
WebRootPath = Path.Combine(AppContext.BaseDirectory, "wwwroot")
});
builder.WebHost.UseKestrel();
builder.WebHost.UseUrls(httpUrl, websocketUrl);
builder.Services.AddRouting();
WebApplication app = builder.Build();
app.UseWebSockets();
app.UseStaticFiles();
app.Map("/r2wars", async context =>
{
if (!context.WebSockets.IsWebSocketRequest)
{
context.Response.StatusCode = StatusCodes.Status400BadRequest;
await context.Response.WriteAsync("A WebSocket connection is required.");
return;
}
using WebSocket socket = await context.WebSockets.AcceptWebSocketAsync();
await r2warsWebSocket.HandleAsync(socket, context.RequestAborted);
});
app.MapFallbackToFile("index.html");
Console.WriteLine("Web server running at " + httpUrl);
Console.WriteLine("WebSocket server running at " + websocketUrl.Replace("http://", "ws://") + "/r2wars");
Console.WriteLine("Press Ctrl-C to stop r2wars.");
if (OperatingSystem.IsWindows())
{
Process.Start(new ProcessStartInfo(httpUrl)
{
UseShellExecute = true
});
}
await app.RunAsync();
}
}
}
+598
View File
@@ -0,0 +1,598 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace r2warsTorneo
{
public class Torneo
{
static readonly List<TournamentTeam> teams = new List<TournamentTeam>();
static readonly List<TournamentRound> rounds = new List<TournamentRound>();
static readonly Dictionary<long, string> teamNames = new Dictionary<long, string>();
static readonly Dictionary<long, string> teamWarriors = new Dictionary<long, string>();
static r2wars r2w;
readonly object lifecycleLock = new object();
readonly object stateLock = new object();
readonly List<TournamentPairing> allcombats = new List<TournamentPairing>();
readonly TournamentTeamScore[] actualcombatscore = { null, null };
readonly string[] actualcombatnames = { "", "" };
readonly string[] actualcombatwarriors = { "", "" };
RoundRobinPairingsGenerator generator;
Task tournamentTask;
string[] loadedWarriors = new string[0];
string loadedArchitecture = "mixed";
string loadedExtension = ".asm";
string fullCombatLog = "";
string actualCombatLog = "";
string actualDeadReason = "";
string warriorsDirectory = "warriors";
string browserWarriorsDirectory = "";
string workflow = "idle";
string workflowMessage = "Load warriors to begin.";
string scores = "No tournament loaded.";
int ncombat;
volatile bool tournamentActive;
volatile bool tournamentAutoRun;
public volatile bool bCombatEnd = true;
public Torneo()
{
r2w = r2warsStatic.r2w;
r2w.Event_combatEnd += new MyHandler1(CombatEnd);
r2w.Event_roundEnd += new MyHandler1(RoundEnd);
r2w.Event_roundExhausted += new MyHandler1(RoundExhausted);
AppDomain.CurrentDomain.ProcessExit += (sender, eventArgs) => CleanupBrowserWarriors();
}
public void SetWarriorsDirectory(string wd)
{
warriorsDirectory = wd;
}
void SendDrawEvent(string value)
{
r2w.send_draw_event(value);
}
void SetWorkflow(string value, string message)
{
lock (stateLock)
{
workflow = value;
workflowMessage = message;
}
}
string BuildStateJson(string console, string summary)
{
lock (stateLock)
{
StringBuilder json = new StringBuilder();
json.Append("{\"workflow\":").Append(JsonUtil.Quote(workflow));
json.Append(",\"message\":").Append(JsonUtil.Quote(workflowMessage));
json.Append(",\"status\":").Append(JsonUtil.Quote(workflowMessage));
json.Append(",\"scores\":").Append(JsonUtil.Quote(scores));
json.Append(",\"completedCombats\":").Append(ncombat);
json.Append(",\"totalCombats\":").Append(allcombats.Count);
if (console != null)
json.Append(",\"console\":").Append(JsonUtil.Quote(console));
if (summary != null)
json.Append(",\"summary\":").Append(JsonUtil.Quote(summary));
json.Append("}");
return json.ToString();
}
}
public string GetStateJson()
{
return BuildStateJson(null, null);
}
void SendState(string console = null, string summary = null)
{
SendDrawEvent(BuildStateJson(console, summary));
}
string BuildScores()
{
if (generator == null || teams.Count < 2)
return "No scores yet.";
StringBuilder result = new StringBuilder();
result.Append("STANDINGS — ").Append(ncombat).Append(" / ").Append(allcombats.Count).Append(" battles complete\n\n");
result.Append("RANK WARRIOR RESULTS\n");
result.Append("---- ---------------------------- -----------------------------------------\n");
try
{
foreach (TournamentRanking standing in generator.GenerateRankings())
{
string name = teamNames[standing.Team.TeamId];
if (name.Length > 28)
name = name.Substring(0, 25) + "...";
result.Append(standing.Rank.ToString().PadLeft(4)).Append(" ");
result.Append(name.PadRight(28)).Append(" ");
result.Append(standing.ScoreDescription).Append("\n");
}
}
catch (InvalidTournamentStateException)
{
result.Append("Standings are being initialized.\n");
}
return result.ToString().TrimEnd();
}
private void RoundEnd(object sender, MyEvent e)
{
if (!tournamentActive)
return;
int round = e.round + 1;
string roundResult = " Round " + round + ": " + e.winnername + " wins (" + e.ciclos + " cycles)\n" +
" Defeat reason: " + e.loserreason + "\n" +
" Instruction: " + e.loserins + "\n";
fullCombatLog += roundResult;
actualCombatLog += roundResult;
actualDeadReason += "Round " + round + " winner: " + e.winnername + "\n" +
" Defeated: " + e.losername + "\n" +
" Reason: " + e.loserreason + "\n" +
" Instruction: " + e.loserins + "\n\n";
if (e.ganador >= 0 && e.ganador < actualcombatscore.Length && actualcombatscore[e.ganador] != null)
actualcombatscore[e.ganador].Score += new HighestPointsScore(1);
scores = BuildScores();
SendState(actualCombatLog);
}
private void RoundExhausted(object sender, MyEvent e)
{
if (!tournamentActive)
return;
int round = e.round + 1;
string timeout = " Round " + round + ": timeout (" + e.ciclos + " cycles)\n";
actualCombatLog += timeout;
fullCombatLog += timeout;
actualDeadReason += timeout;
SendState(actualCombatLog);
}
private void CombatEnd(object sender, MyEvent e)
{
if (!tournamentActive)
return;
actualCombatLog += "Battle winner: " + e.winnername + "\n";
fullCombatLog += "Battle winner: " + e.winnername + "\n";
actualDeadReason += "Winner: " + e.winnername + "\n";
ncombat++;
bCombatEnd = true;
scores = BuildScores();
if (ncombat >= allcombats.Count)
{
FinishTournament();
return;
}
if (!tournamentAutoRun || r2w.bStopAtRoundStart)
{
tournamentAutoRun = false;
SetWorkflow("paused", "Battle complete. Resume for the next battle, or Step through it one cycle at a time.");
}
else
{
SetWorkflow("running", "Battle complete. Starting the next battle…");
}
SendState(actualCombatLog, actualDeadReason);
}
bool PrepareNextCombat(bool autoStart)
{
lock (lifecycleLock)
{
if (!tournamentActive || !bCombatEnd || ncombat >= allcombats.Count)
return false;
int player = 0;
foreach (TournamentTeamScore teamScore in allcombats[ncombat].TeamScores)
{
actualcombatnames[player] = teamNames[teamScore.Team.TeamId];
actualcombatwarriors[player] = teamWarriors[teamScore.Team.TeamId];
actualcombatscore[player] = teamScore;
actualcombatscore[player].Score += new HighestPointsScore(0);
player++;
}
actualCombatLog = "Battle " + (ncombat + 1) + " / " + allcombats.Count + ": " +
actualcombatnames[0] + " vs " + actualcombatnames[1] + "\n";
actualDeadReason = actualcombatnames[0] + " vs " + actualcombatnames[1] + "\n\n";
fullCombatLog += actualCombatLog;
bCombatEnd = false;
if (autoStart)
SetWorkflow("running", "Battle " + (ncombat + 1) + " / " + allcombats.Count + " is running.");
else
SetWorkflow("paused", "Battle " + (ncombat + 1) + " / " + allcombats.Count + " is ready. Step advances one cycle; Resume runs continuously.");
SendState(actualCombatLog);
bool initialized = r2w.playcombat(
actualcombatwarriors[0], actualcombatwarriors[1],
actualcombatnames[0], actualcombatnames[1], false, autoStart);
if (!initialized)
{
bCombatEnd = true;
tournamentAutoRun = false;
SetWorkflow("paused", "The battle could not be initialized. Check the warrior files, then reload them.");
SendState();
}
return initialized;
}
}
void FinishTournament()
{
lock (lifecycleLock)
{
if (workflow == "finished")
return;
tournamentAutoRun = false;
tournamentActive = false;
bCombatEnd = true;
fullCombatLog += "Tournament finished " + DateTime.Now + "\n";
scores = BuildScores();
SetWorkflow("finished", "Tournament complete. Review the final standings or choose Play again to reset all scores.");
SendState(fullCombatLog, scores + "\n\nLAST BATTLE\n\n" + actualDeadReason);
SaveTournamentReport();
}
}
void SaveTournamentReport()
{
try
{
string filename = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".r2wars.txt";
using (StreamWriter writer = File.CreateText(filename))
{
writer.WriteLine(scores);
writer.WriteLine();
writer.WriteLine("FULL LOG");
writer.WriteLine("========");
writer.Write(fullCombatLog);
}
}
catch (Exception exception)
{
Console.Error.WriteLine("Could not save tournament report: " + exception.Message);
}
}
void TournamentLoop()
{
while (tournamentActive)
{
if (tournamentAutoRun && bCombatEnd)
PrepareNextCombat(true);
else
Thread.Sleep(50);
}
}
bool BeginTournament()
{
if (allcombats.Count == 0 || loadedWarriors.Length < 2)
{
SetWorkflow("idle", "At least two warriors must be loaded before starting a tournament.");
SendState();
return false;
}
if (workflow == "finished")
{
SetWorkflow("finished", "This tournament is complete. Choose Play again to reset the scores first.");
SendState();
return false;
}
if (tournamentActive)
return true;
fullCombatLog = "Tournament started " + DateTime.Now + "\n";
tournamentActive = true;
bCombatEnd = true;
tournamentTask = Task.Factory.StartNew(TournamentLoop);
return true;
}
public void StopTournament()
{
tournamentAutoRun = false;
tournamentActive = false;
lock (lifecycleLock)
{
r2w.CancelCombat();
bCombatEnd = true;
}
Task task = tournamentTask;
if (task != null && !task.IsCompleted)
task.Wait(2000);
}
public string getemptymemory()
{
StringBuilder memory = new StringBuilder();
for (int index = 0; index < 1024; index++)
{
if (index > 0)
memory.Append(',');
memory.Append("\"\"");
}
return memory.ToString();
}
private void CreatePairings(string[] selectedfiles, string architecture, string extension)
{
r2w.ClearHistory();
allcombats.Clear();
teamNames.Clear();
teamWarriors.Clear();
rounds.Clear();
teams.Clear();
ncombat = 0;
fullCombatLog = "";
actualCombatLog = "";
actualDeadReason = "";
loadedWarriors = (string[])selectedfiles.Clone();
loadedArchitecture = architecture;
loadedExtension = extension;
generator = new RoundRobinPairingsGenerator();
generator.Reset();
for (int index = 0; index < selectedfiles.Length; index++)
{
TournamentTeam team = new TournamentTeam(index, 0);
teams.Add(team);
string filename = Path.GetFileName(selectedfiles[index]);
string name = filename.EndsWith(extension, StringComparison.OrdinalIgnoreCase)
? filename.Substring(0, filename.Length - extension.Length)
: filename;
teamNames.Add(index, name);
teamWarriors.Add(index, selectedfiles[index]);
}
while (true)
{
generator.Reset();
generator.LoadState(teams, rounds);
TournamentRound round = generator.CreateNextRound(null);
if (round == null)
break;
rounds.Add(round);
}
foreach (TournamentRound round in rounds)
foreach (TournamentPairing pairing in round.Pairings)
allcombats.Add(pairing);
string console = "Tournament architecture: " + architecture + "\n" +
"Warriors directory: " + warriorsDirectory + "\n" +
"Loaded warriors (" + selectedfiles.Length + "):";
foreach (string warrior in selectedfiles)
console += "\n • " + Path.GetFileName(warrior);
if (selectedfiles.Length < 2)
{
scores = "No tournament loaded.";
SetWorkflow("idle", "At least two .asm warriors are required. Add warriors, then load again.");
console += "\n\nAt least two warriors are required to start a tournament.";
}
else
{
scores = BuildScores();
SetWorkflow("ready", selectedfiles.Length + " warriors loaded for " + allcombats.Count + " battles. Start the tournament when ready.");
console += "\n\nReady for " + allcombats.Count + " round-robin battles.";
}
string resetDisplay = "{\"player1\":{\"regs\":\"\",\"code\":\"\",\"name\":\"Player 1\"}," +
"\"player2\":{\"regs\":\"\",\"code\":\"\",\"name\":\"Player 2\"}," +
"\"memory\":[" + getemptymemory() + "],\"activePlayer\":-1," +
"\"historyPosition\":0,\"historyCount\":0,\"canBrowseEarlier\":false,\"canBrowseLater\":false}";
SendDrawEvent(resetDisplay);
SendState(console);
}
public void LoadTournamentPlayers()
{
StopTournament();
CleanupBrowserWarriors();
string[] files;
try
{
files = Directory.GetFiles(warriorsDirectory)
.Where(path => path.EndsWith(".asm", StringComparison.OrdinalIgnoreCase))
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
.ToArray();
}
catch (Exception exception)
{
loadedWarriors = new string[0];
scores = "No tournament loaded.";
SetWorkflow("idle", "The warriors directory could not be read: " + exception.Message);
SendDrawEvent("nowarriors");
SendState();
return;
}
CreatePairings(files, "mixed (detected from each filename)", ".asm");
}
public List<BrowserWarriorSource> GetWarriorSources()
{
string[] files = loadedWarriors.Where(File.Exists).ToArray();
if (files.Length == 0)
{
if (!Directory.Exists(warriorsDirectory))
return new List<BrowserWarriorSource>();
files = Directory.GetFiles(warriorsDirectory)
.Where(path => path.EndsWith(".asm", StringComparison.OrdinalIgnoreCase))
.OrderBy(path => path, StringComparer.OrdinalIgnoreCase)
.ToArray();
}
return files.Select(path => new BrowserWarriorSource
{
Name = Path.GetFileName(path),
Source = File.ReadAllText(path)
}).ToList();
}
public void LoadTournamentSources(IReadOnlyList<BrowserWarriorSource> warriors)
{
if (warriors == null)
throw new ArgumentNullException(nameof(warriors));
if (warriors.Count > 128)
throw new InvalidOperationException("A tournament cannot contain more than 128 bots.");
HashSet<string> names = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (BrowserWarriorSource warrior in warriors)
{
string name = (warrior?.Name ?? "").Trim();
if (name.Length == 0 || name != Path.GetFileName(name) || name.Contains('/') || name.Contains('\\') ||
name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
throw new InvalidOperationException("Bot filenames must not contain a directory path.");
if (!name.EndsWith(".asm", StringComparison.OrdinalIgnoreCase))
throw new InvalidOperationException(name + ": filename must end in .asm");
if (WarriorCompiler.ArchitectureFromName(name) == r2archs.eArch.unknown)
throw new InvalidOperationException(name + ": architecture must be encoded in the filename");
if (!names.Add(name))
throw new InvalidOperationException("Duplicate bot filename: " + name);
if (string.IsNullOrWhiteSpace(warrior.Source))
throw new InvalidOperationException(name + ": source is empty");
}
StopTournament();
string directory = Path.Combine(Path.GetTempPath(), "r2wars-web-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(directory);
try
{
string[] files = warriors
.OrderBy(warrior => warrior.Name, StringComparer.OrdinalIgnoreCase)
.Select(warrior =>
{
string path = Path.Combine(directory, warrior.Name.Trim());
File.WriteAllText(path, warrior.Source);
return path;
}).ToArray();
CleanupBrowserWarriors();
browserWarriorsDirectory = directory;
CreatePairings(files, "mixed (browser sources)", ".asm");
}
catch
{
try { Directory.Delete(directory, true); }
catch (IOException) { }
catch (UnauthorizedAccessException) { }
throw;
}
}
private void CleanupBrowserWarriors()
{
if (string.IsNullOrEmpty(browserWarriorsDirectory))
return;
string directory = browserWarriorsDirectory;
browserWarriorsDirectory = "";
try { Directory.Delete(directory, true); }
catch (IOException) { }
catch (UnauthorizedAccessException) { }
}
public void ResetTournament()
{
StopTournament();
if (loadedWarriors.Length < 2)
{
LoadTournamentPlayers();
return;
}
CreatePairings(loadedWarriors, loadedArchitecture, loadedExtension);
}
public void StopActualCombat()
{
if (workflow != "running")
return;
tournamentAutoRun = false;
lock (lifecycleLock)
r2w.StopCombate();
if (workflow != "finished")
{
SetWorkflow("paused", "Paused. Resume continuous play or Step exactly one cycle.");
SendState();
}
}
public void StepTournamentCombats()
{
if (workflow != "paused")
return;
if (!BeginTournament())
return;
tournamentAutoRun = false;
if (bCombatEnd && !PrepareNextCombat(false))
return;
if (!r2w.bThreadIni && r2w.bInCombat)
r2w.stepCombate();
if (workflow != "finished")
{
SetWorkflow("paused", "Paused after one cycle. Step again or Resume continuous play.");
SendState();
}
}
public void RunTournamentCombats()
{
if (workflow != "ready" && workflow != "paused")
return;
if (!BeginTournament())
return;
tournamentAutoRun = true;
SetWorkflow("running", "Tournament running. Pause at any time to inspect or step.");
SendState();
if (!bCombatEnd && r2w.bInCombat && !r2w.bThreadIni)
r2w.iniciaCombate();
}
}
internal static class JsonUtil
{
public static string Quote(string value)
{
if (value == null)
return "null";
StringBuilder result = new StringBuilder(value.Length + 2);
result.Append('"');
foreach (char character in value)
{
switch (character)
{
case '"': result.Append("\\\""); break;
case '\\': result.Append("\\\\"); break;
case '\b': result.Append("\\b"); break;
case '\f': result.Append("\\f"); break;
case '\n': result.Append("\\n"); break;
case '\r': result.Append("\\r"); break;
case '\t': result.Append("\\t"); break;
default:
if (character < 32)
result.Append("\\u").Append(((int)character).ToString("x4"));
else
result.Append(character);
break;
}
}
result.Append('"');
return result.ToString();
}
}
}
@@ -3,7 +3,6 @@
/// <summary>
/// Thrown when an IPairingsGenerator is asked to load a state that does not represent a valid tournament within its constraints.
/// </summary>
[global::System.Serializable]
public class InvalidTournamentStateException : Exception
{
/// <summary>
@@ -32,16 +31,4 @@
: base(message, inner)
{
}
/// <summary>
/// Initializes a new instance of the InvalidTournamentStateException class with serialized data.
/// </summary>
/// <param name="info">The System.Runtime.Serialization.SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The System.Runtime.Serialization.StreamingContext that contains contextual information about the source or destination.</param>
/// <exception cref="System.ArgumentNullException">The info parameter is null.</exception>
/// <exception cref="System.Runtime.Serialization.SerializationException">The class name is null or System.Exception.HResult is zero (0).</exception>
protected InvalidTournamentStateException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -386,11 +386,11 @@
lastRecord = rank.Record;
lastRank = rank.Rank;
string scoreDescription = String.Format("{0:F} ({1}-{2}-{3} with {4} overall).", rank.Record.WinRecord, rank.Record.Wins, rank.Record.Draws, rank.Record.Losses, rank.Record.OverallScore);
string roundWins = rank.Record.OverallScore == null ? "0" : rank.Record.OverallScore.ToString();
string scoreDescription = String.Format("{0:0.0} match pts · {1}W {2}D {3}L · {4} round wins", rank.Record.WinRecord, rank.Record.Wins, rank.Record.Draws, rank.Record.Losses, roundWins);
yield return new TournamentRanking(rank.Team, rank.Rank, scoreDescription);
}
yield break;
}
}
+106
View File
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace r2warsTorneo
{
public sealed class BrowserWarriorSource
{
public string Name { get; set; } = "";
public string Source { get; set; } = "";
}
public sealed class WarriorAssemblyResult
{
public bool Ok { get; set; }
public byte[] Bytes { get; set; } = Array.Empty<byte>();
public int Size { get { return Bytes.Length; } }
public string Message { get; set; } = "";
}
public static class WarriorCompiler
{
public const int MaximumWarriorSize = 512;
public static r2archs.eArch ArchitectureFromName(string name)
{
return r2archs.archfromfileext((name ?? "").ToLowerInvariant());
}
public static WarriorAssemblyResult Assemble(BrowserWarriorSource warrior)
{
if (warrior == null)
return Failure("No bot source was provided.");
r2archs.eArch architecture = ArchitectureFromName(warrior.Name);
if (architecture == r2archs.eArch.unknown)
return Failure((warrior.Name ?? "Unnamed bot") + ": architecture must be encoded in the filename");
if (string.IsNullOrWhiteSpace(warrior.Source))
return Failure((warrior.Name ?? "Unnamed bot") + ": source is empty");
if (warrior.Source.Length > 64 * 1024)
return Failure((warrior.Name ?? "Unnamed bot") + ": source is too large to preview");
string temporaryFile = Path.Combine(Path.GetTempPath(), "r2wars-assemble-" + Guid.NewGuid().ToString("N") + ".asm");
try
{
File.WriteAllText(temporaryFile, warrior.Source);
ProcessStartInfo startInfo = new ProcessStartInfo
{
FileName = r2paths.rasm2,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
foreach (string argument in r2archs.rasm2param(architecture).Split(' ', StringSplitOptions.RemoveEmptyEntries))
startInfo.ArgumentList.Add(argument);
startInfo.ArgumentList.Add("-f");
startInfo.ArgumentList.Add(temporaryFile);
using Process process = Process.Start(startInfo);
if (process == null)
return Failure("rasm2 could not be started.");
Task<string> stdoutTask = process.StandardOutput.ReadToEndAsync();
Task<string> stderrTask = process.StandardError.ReadToEndAsync();
process.WaitForExit();
string stdout = stdoutTask.GetAwaiter().GetResult();
string stderr = stderrTask.GetAwaiter().GetResult().Trim();
string hex = new string(stdout.Where(character => !char.IsWhiteSpace(character)).ToArray());
if (process.ExitCode != 0 || hex.Length == 0 || hex.Length % 2 != 0 || !hex.All(Uri.IsHexDigit))
return Failure(stderr.Length > 0 ? stderr : "rasm2 could not assemble this bot.");
byte[] bytes = new byte[hex.Length / 2];
for (int index = 0; index < bytes.Length; index++)
bytes[index] = Convert.ToByte(hex.Substring(index * 2, 2), 16);
bool oversized = bytes.Length > MaximumWarriorSize;
return new WarriorAssemblyResult
{
Ok = !oversized,
Bytes = bytes,
Message = oversized
? "Compiles, but exceeds the " + MaximumWarriorSize + "-byte warrior limit."
: "Compiles successfully."
};
}
catch (Exception exception)
{
return Failure(exception.Message);
}
finally
{
try { File.Delete(temporaryFile); }
catch (IOException) { }
catch (UnauthorizedAccessException) { }
}
}
private static WarriorAssemblyResult Failure(string message)
{
return new WarriorAssemblyResult { Ok = false, Message = message };
}
}
}
+1095
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -68,6 +68,7 @@ public class R2Pipe : IR2Pipe, System.IDisposable
r2Process.Start();
r2Process.StandardInput.AutoFlush = true;
r2Process.StandardInput.NewLine = "\n";
// ignore first run
r2Process.StandardOutput.Read();
// Console.WriteLine(r2Process.StandardOutput.Read());
+1
View File
@@ -0,0 +1 @@
../examples
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
(
for a in warriors/* ; do
if [ "`echo $a | grep txt$`" ]; then
continue;
fi
printf "$a "
if [ "`echo $a | grep x86-32`" ]; then
rasm2 -a x86 -b 32 -f $a |wc -c
elif [ "`echo $a | grep arm-64`" ]; then
rasm2 -a arm -b 64 -f $a |wc -c
elif [ "`echo $a | grep arm-16`" ]; then
rasm2 -a arm -b 16 -f $a |wc -c
elif [ "`echo $a | grep mips-32`" ]; then
rasm2 -a mips -b 32 -f $a |wc -c
elif [ "`echo $a | grep 8051`" ]; then
rasm2 -a 8051 -f $a |wc -c
fi
done
) |awk '{print $2"\t"$1}'
+749
View File
@@ -0,0 +1,749 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
namespace r2warsTorneo
{
public class r2wars
{
private const int MAX_CYCLES = 2000;
private const int MAX_HISTORY_STATES = 2048;
private sealed class UiHistoryEntry
{
public string Regs1;
public string Code1;
public string Regs2;
public string Code2;
public string Memory;
public string Status;
public int ActivePlayer;
}
public clsEngine Engine = null;
public bool bThreadIni = false;
public bool bStopProcess = false;
public bool bInCombat = false;
public bool sync_var = false;
public bool bStopAtRoundEnd = false;
public bool bStopAtRoundStart = false;
public event MyHandler1 Event_draw;
public event MyHandler1 Event_roundEnd;
public event MyHandler1 Event_combatEnd;
public event MyHandler1 Event_roundExhausted;
public string answer = "";
string[] pColor = { "b", "r" };
string[] cRead = { "q", "y" };
string[] cWrite = { "v", "o" };
string[] rr = { "", "" };
string[] dd = { "", "" };
string[] memoria = new string[1024];
readonly object historyLock = new object();
readonly List<UiHistoryEntry> uiHistory = new List<UiHistoryEntry>();
int historyIndex = -1;
string status = "Idle";
int[] victorias = { 0, 0 };
int totalciclos = 0;
int nRound = 0;
public int nExausted = 0;
bool bDead = false;
bool bSingleRound = false;
Task gameLoopTask = null;
public r2wars()
{
if (Engine == null)
Engine = new clsEngine();
initmemoria();
}
public void send_draw_event(string s)
{
// this pause is magic
// Firefox can free memory
// chrome never consume memory and work smooth on drawing
Thread.Sleep(5);
MyEvent e1 = new MyEvent();
e1.message = s;
if (Event_draw != null)
{
Event_draw(0, e1);
/*
Task t = Task.Factory.StartNew(() =>
{
while (!sync_var)
{
Thread.Sleep(10);
}
});
t.Wait();
*/
}
e1 = null;
}
string json_output(UiHistoryEntry historyEntry = null)
{
string username1 = Engine.GetUserName(0);
string username2 = Engine.GetUserName(1);
string regs1;
string code1;
string regs2;
string code2;
string memory;
string outputStatus;
int activePlayer;
int historyPosition;
int historyCount;
bool canBrowseEarlier;
bool canBrowseLater;
if (historyEntry == null)
{
lock (rr)
{
regs1 = rr[0];
regs2 = rr[1];
}
lock (dd)
{
code1 = dd[0];
code2 = dd[1];
}
memory = getmemoria();
outputStatus = status;
activePlayer = Engine != null && bInCombat ? Engine.thisplayer : -1;
}
else
{
regs1 = historyEntry.Regs1;
code1 = historyEntry.Code1;
regs2 = historyEntry.Regs2;
code2 = historyEntry.Code2;
memory = historyEntry.Memory;
outputStatus = historyEntry.Status;
activePlayer = historyEntry.ActivePlayer;
}
lock (historyLock)
{
historyCount = uiHistory.Count;
historyPosition = historyIndex >= 0 ? historyIndex + 1 : 0;
canBrowseEarlier = historyIndex > 0;
canBrowseLater = historyIndex >= 0 && historyIndex < uiHistory.Count - 1;
}
if (historyEntry != null)
{
string location = historyPosition == historyCount ? "Latest state" :
"History " + historyPosition + " / " + historyCount;
outputStatus = location + " — " + outputStatus;
}
string salida = "{\"player1\":{\"regs\":" + JsonUtil.Quote(regs1) + ",\"code\":" + JsonUtil.Quote(code1) + ",\"name\":" + JsonUtil.Quote(username1) + "}," +
"\"player2\":{\"regs\":" + JsonUtil.Quote(regs2) + ",\"code\":" + JsonUtil.Quote(code2) + ",\"name\":" + JsonUtil.Quote(username2) + "}," +
"\"memory\":[" + memory + "],\"status\":" + JsonUtil.Quote(outputStatus) + ",\"activePlayer\":" + activePlayer.ToString() +
",\"historyPosition\":" + historyPosition.ToString() + ",\"historyCount\":" + historyCount.ToString() +
",\"canBrowseEarlier\":" + (canBrowseEarlier ? "true" : "false") +
",\"canBrowseLater\":" + (canBrowseLater ? "true" : "false") + "}";
return salida;
}
private void PublishCurrentState()
{
UiHistoryEntry entry = new UiHistoryEntry();
lock (rr)
{
entry.Regs1 = rr[0];
entry.Regs2 = rr[1];
}
lock (dd)
{
entry.Code1 = dd[0];
entry.Code2 = dd[1];
}
entry.Memory = getmemoria();
entry.Status = status;
entry.ActivePlayer = Engine != null && bInCombat ? Engine.thisplayer : -1;
lock (historyLock)
{
uiHistory.Add(entry);
if (uiHistory.Count > MAX_HISTORY_STATES)
uiHistory.RemoveAt(0);
historyIndex = uiHistory.Count - 1;
}
send_draw_event(json_output());
}
public void ClearHistory()
{
lock (historyLock)
{
uiHistory.Clear();
historyIndex = -1;
}
}
public void initmemoria()
{
for (int x = 0; x < 1024; x++)
memoria[x] = "\"\"";
}
public string getmemoria()
{
lock (memoria)
{
string salida = "";
for (int x = 0; x < 1024; x++)
salida += memoria[x] + ",";
return salida.Remove(salida.Length - 1);
}
}
void pinta(long offset, string c, string s)
{
lock (memoria)
{
if (offset>=0 && offset<Engine.memsize)
memoria[offset] = "\"" + c + s + "\"";
}
}
void pinta(long offset, string c,string s,int count)
{
lock (memoria)
{
while ((count--) != 0)
if (offset >= 0 && offset < 1024)
memoria[offset++] = "\"" + c + s + "\"";
//else
// Console.WriteLine("Zascaaaaa");
}
}
public void testpinta()
{
initmemoria();
pinta(1023, "F");
pinta(0, "F");
PublishCurrentState();
}
void pinta(int offset, string c)
{
lock (memoria)
{
if (offset >= 0 && offset < Engine.memsize)
memoria[offset] = "\"" + c + "\"";
}
}
void pinta(int offset, int count, string c)
{
lock (memoria)
{
while ((count--) != 0)
if (offset >= 0 && offset < 1024)
memoria[offset++] = "\"" + c + "\"";
//else
// Console.WriteLine("Zascaaaaa");
}
}
void drawplayerturn(int nplayer)
{
}
string padlines(string t,int maxlen=54)
{
string b = "";
string[] lineas = t.Split('\n');
foreach (string l in lineas)
{
if (l.Length > maxlen)
b += l.Substring(0, maxlen) + "\n";
else
{
string pad = "";
for (int n = 0; n < maxlen - l.Length; n++)
pad += " ";
b += l + pad + "\n";
}
}
return b;
}
void drawPC(int nplayer)
{
long oldPC = Engine.players[nplayer].actual.oldpc;
if (oldPC >= 0 && oldPC <= Engine.memsize)
{
pinta(oldPC, pColor[nplayer], "", Engine.players[nplayer].actual.oldpcsize);
}
long aPC = Engine.players[nplayer].actual.ipc();
// ponemos la X en la posicion nueva
if (aPC >= 0 && aPC <= Engine.memsize)
{
pinta(aPC, pColor[nplayer], "X", Engine.players[nplayer].actual.pcsize);
}
}
void drawscreen(int nplayer)
{
// seleccionamos el offset actual y lo pintamos invertido
string dasm = padlines(Engine.players[nplayer].actual.dasm);
string actual = padlines(Engine.players[nplayer].actual.ins);
int i = dasm.IndexOf(actual);
if (i != -1)
{
dasm = dasm.Insert(i + actual.Length, "</span>");
dasm = dasm.Insert(i, "<span class='s'>");
}
lock (dd)
{
dd[nplayer] = "Cycles:" + Engine.players[nplayer].actual.cycles.ToString() + "\nActual Instruction:\n " + padlines(Engine.players[nplayer].actual.ins.Substring(16)) + "\n" + dasm;
}
lock (rr)
{
rr[nplayer] = Engine.players[nplayer].actual.formatregs();
}
}
void drawmemaccess(int nplayer)
{
Dictionary<int, int> dicMemRead = Engine.GetMemAccessReadDict(Engine.players[nplayer].actual.mem);
Dictionary<int, int> dicMemWrite = Engine.GetMemAccessWriteDict(Engine.players[nplayer].actual.mem);
if (dicMemRead.Count > 0)
{
foreach (var i in dicMemRead)
{
if (i.Key >= 0 && i.Key <= Engine.memsize)
{
for (int x = 0; x < i.Value; x++)
pinta(i.Key + x, cRead[nplayer],"R");
}
}
}
if (dicMemWrite.Count > 0)
{
foreach (var i in dicMemWrite)
{
if (i.Key >= 0 && i.Key <= Engine.memsize)
{
for (int x = 0; x < i.Value; x++)
{
pinta(i.Key + x, cWrite[nplayer],"W");
}
}
}
}
}
private void resetTablero()
{
initmemoria();
pinta(Engine.GetAddressProgram(0), Engine.GetSizeProgram(0), "b");
pinta(Engine.GetAddressProgram(1), Engine.GetSizeProgram(1), "r");
}
private void update(int n)
{
if (bDead)
{
drawplayerturn(Engine.thisplayer);
}
else
{
// Dibujamos la info del jugador
drawscreen(Engine.thisplayer);
drawPC(Engine.thisplayer);
// dibujamos la info del nuevo jugador
drawscreen(Engine.otherplayer);
drawPC(Engine.otherplayer);
// ponemos el marco del jugador actual
drawplayerturn(Engine.otherplayer);
// Dibujamos los accesos a memoria
drawmemaccess(Engine.thisplayer);
}
PublishCurrentState();
}
private void RoundExhausted()
{
Debug.WriteLine("RoundExhausted::Invoked.");
// Actualizamos la pantalla indicando que pinte los programas
if (Event_roundExhausted != null)
{
MyEvent e3 = new MyEvent();
e3.message = "";
e3.ganador = 0;
e3.round = nRound;
e3.ciclos = totalciclos;
e3.winnername = "";
Event_roundExhausted(this, e3);
}
}
private void RoundEnd()
{
// notificamos fin del round
Debug.WriteLine("RoundEnd::Invoked.");
if (Event_roundEnd != null)
{
MyEvent e2 = new MyEvent();
e2.message = "";
e2.ganador = Engine.thisplayer;
e2.round = nRound;
e2.ciclos = totalciclos;
e2.winnername = Engine.players[Engine.thisplayer].name;
e2.loserins = Engine.players[Engine.otherplayer].actual.deadins;
e2.loserreason = Engine.players[Engine.otherplayer].actual.deadinfo;
e2.losername = Engine.players[Engine.otherplayer].name;
Event_roundEnd(this, e2);
}
}
private void CombatEnd(bool empate=false)
{
Debug.WriteLine("CombatEnd::Invoked.");
status = "Battle complete";
if (Event_combatEnd != null)
{
MyEvent e1 = new MyEvent();
e1.message = "";
if (victorias[0] > victorias[1])
{
e1.ganador = 0;
e1.perdedor = 1;
}
else
{
e1.ganador = 1;
e1.perdedor = 0;
}
e1.round = nRound;
e1.ciclos = totalciclos;
if (!empate)
{
e1.winnername = Engine.players[e1.ganador].name;
}
else
e1.winnername = "Draw";
this.Event_combatEnd(this, e1);
}
}
private void espera(int veces, int pausa = 1)
{
Task t = Task.Factory.StartNew(() =>
{
int n = veces;
while ((n--) > 0)
{
System.Threading.Thread.Sleep(pausa);
}
});
t.Wait();
}
private void ExecuteRoundInstruction(bool bWait)
{
if (Engine.cyleszero())
{
// Realizamos el STEP
bDead = Engine.stepInfoNew(getmemoria());
//update(1);
if (bDead)
{
Console.WriteLine("dead");
}
else
{
// Dibujamos la info del jugador
drawPC(Engine.thisplayer);
// dibujamos la info del nuevo jugador
drawPC(Engine.otherplayer);
// Dibujamos los accesos a memoria
drawmemaccess(Engine.thisplayer);
drawplayerturn(Engine.otherplayer);
drawscreen(Engine.thisplayer);
drawscreen(Engine.otherplayer);
PublishCurrentState();
}
}
else
{
//Engine.players[Engine.thisplayer].logAdd(new clsinfo(Engine.players[Engine.thisplayer].actual.pc, Engine.players[Engine.thisplayer].actual.ins, Engine.players[Engine.thisplayer].actual.dasm, Engine.players[Engine.thisplayer].actual.regs, Engine.players[Engine.thisplayer].actual.mem, Engine.players[Engine.thisplayer].actual.cycles + 1, getmemoria()));
drawplayerturn(Engine.otherplayer);
drawscreen(Engine.thisplayer);
drawscreen(Engine.otherplayer);
PublishCurrentState();
}
// here was have a pause on previous versions now its on send_draw_event
Engine.switchUserIdx();
}
public bool iniciaJugadores(string rutaWarrior1, string rutaWarrior2, string nameWarrior1, string nameWarrior2)
{
ClearHistory();
initmemoria();
string res = Engine.Init(new string[] {
rutaWarrior1,
rutaWarrior2
},
new string[] {
nameWarrior1,
nameWarrior2
}
);
Console.WriteLine("RES = " + res);
if (res == "OK")
{
// seteamos el jugador 1
Engine.switchUser(1);
pinta(Engine.GetAddressProgram(), Engine.GetSizeProgram(), "r");
// dibujamos la pantalla del jugador 1
drawscreen(1);//, Engine.players[1].actual.ins, Engine.players[1].actual.dasm, Engine.players[1].actual.regs, Engine.players[1].actual.ipc());
drawPC(1);
// seteamos el jugador 0
Engine.switchUser(0);
pinta(Engine.GetAddressProgram(), Engine.GetSizeProgram(), "b");
// dibujamos la pantalla del jugador 0
drawscreen(0);//, Engine.players[0].actual.ins, Engine.players[0].actual.dasm, Engine.players[0].actual.regs, Engine.players[0].actual.ipc());
drawPC(0);
// ponemos el marco en el jugador0
drawplayerturn(0);
return true;
}
return false;
}
bool bResetArena = false;
public void stepCombate()
{
Debug.WriteLine("r2wars:stepCombate");
status = "Paused — advanced 1 cycle";
if (bInCombat)
{
if (!bDead)
{
if (bResetArena)
{
bResetArena = false;
Engine.ReiniciaGame(true);
// Actualizamos la pantalla indicando que pinte los programas
resetTablero();
drawPC(Engine.thisplayer);
drawPC(Engine.otherplayer);
drawscreen(Engine.thisplayer);
drawscreen(Engine.otherplayer);
PublishCurrentState();
return;
}
totalciclos++;
if (totalciclos > MAX_CYCLES)
{
nExausted++;
if (nExausted > 2)
{
bInCombat = false;
bThreadIni = false;
bStopProcess = false;
RoundExhausted();
CombatEnd(true);
nExausted = 0;
return;
}
else
{
RoundExhausted();
totalciclos = 0;
bResetArena = true;
return;
}
}
ExecuteRoundInstruction(false);
}
else
{
victorias[Engine.thisplayer]++;
if (nRound == 3 || victorias[1] == 2 || victorias[0] == 2)
{
bInCombat = false;
bThreadIni = false;
bStopProcess = false;
RoundEnd();
CombatEnd();
}
else
{
RoundEnd();
bDead = false;
totalciclos = 0;
bResetArena = true;
nRound++;
}
}
}
}
public void iniciaCombate()
{
status = "Running";
bThreadIni = true;
gameLoopTask = Task.Factory.StartNew(() =>
{
// Jugamos el combate mientras no hayan muertos
Debug.WriteLine("gameLoopTask: Ini.");
//int nexausted = 0;
while (bInCombat)
{
while (!bDead)
{
if (bStopProcess)
{
bThreadIni = false;
bStopProcess = false;
Debug.WriteLine("gameLoopTask: Fin (stopprocess).");
return;
}
if (bResetArena)
{
bResetArena = false;
Engine.ReiniciaGame(true);
// Actualizamos la pantalla indicando que pinte los programas
resetTablero();
drawPC(Engine.thisplayer);
drawPC(Engine.otherplayer);
drawscreen(Engine.thisplayer);
drawscreen(Engine.otherplayer);
PublishCurrentState();
if (bStopAtRoundEnd)
{
bThreadIni = false;
return;
}
}
totalciclos++;
if (totalciclos > MAX_CYCLES)
{
nExausted++;
if (nExausted > 2)
{
bInCombat = false;
bThreadIni = false;
bStopProcess = false;
RoundExhausted();
CombatEnd(true);
nExausted = 0;
Debug.WriteLine("gameLoopTask: Fin(draw)");
return;
}
else
{
RoundExhausted();
totalciclos = 0;
bResetArena = true;
if (bStopAtRoundEnd)
{
bThreadIni = false;
return;
}
}
}
ExecuteRoundInstruction(false);
}
victorias[Engine.thisplayer]++;
if (nRound == 3 || victorias[1] == 2 || victorias[0] == 2)
{
bInCombat = false;
bThreadIni = false;
bStopProcess = false;
RoundEnd();
CombatEnd();
break;
}
else
{
RoundEnd();
bDead = false;
totalciclos = 0;
bResetArena = true;
nRound++;
if (bStopAtRoundEnd)
{
bThreadIni = false;
break;
}
}
}
Debug.WriteLine("gameLoopTask: Fin");
});
}
public bool playcombat(string rutaWarrior1, string rutaWarrior2, string nameWarrior1, string nameWarrior2, bool bSingleRound, bool autoStart)
{
if (iniciaJugadores(rutaWarrior1, rutaWarrior2, nameWarrior1, nameWarrior2))
{
// ejecutamos el combate
this.bInCombat = true; // indicamos que estamos en un combate
this.bSingleRound = bSingleRound; // indicamos que No queremos un unico round
this.bStopProcess = false;
this.victorias[0] = 0;
this.victorias[1] = 0;
this.nRound = 0;
this.nExausted = 0;
this.bDead = false;
this.totalciclos = 0;
status = autoStart ? "Running" : "Paused — ready to step";
PublishCurrentState();
if (autoStart)
{
iniciaCombate();
}
return true;
}
return false;
}
public void StopCombate()
{
while (bThreadIni)
{
this.bStopProcess = true;
Thread.Sleep(100);
}
if (bInCombat)
status = "Paused";
}
public void CancelCombat()
{
StopCombate();
bInCombat = false;
bStopProcess = false;
bThreadIni = false;
status = "Idle";
}
public string prevLog()
{
UiHistoryEntry entry;
lock (historyLock)
{
if (historyIndex <= 0 || uiHistory.Count == 0)
return "";
historyIndex--;
entry = uiHistory[historyIndex];
}
return json_output(entry);
}
public string nextLog()
{
UiHistoryEntry entry;
lock (historyLock)
{
if (historyIndex < 0 || historyIndex >= uiHistory.Count - 1)
return "";
historyIndex++;
entry = uiHistory[historyIndex];
}
return json_output(entry);
}
}
}
+16
View File
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>r2warsTorneo</RootNamespace>
<AssemblyName>r2wars</AssemblyName>
<AssemblyTitle>r2wars</AssemblyTitle>
<Product>r2wars</Product>
<Version>0.4.0</Version>
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Content Update="wwwroot/**" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
+22
View File
@@ -0,0 +1,22 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "r2wars", "r2wars.csproj", "{7C07AB0A-D2B5-4546-B5B2-6DC6E77E40D1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7C07AB0A-D2B5-4546-B5B2-6DC6E77E40D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C07AB0A-D2B5-4546-B5B2-6DC6E77E40D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C07AB0A-D2B5-4546-B5B2-6DC6E77E40D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C07AB0A-D2B5-4546-B5B2-6DC6E77E40D1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+251
View File
@@ -0,0 +1,251 @@
using System;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
namespace r2warsTorneo
{
public static class r2warsWebSocket
{
private const int MaxMessageSize = 1024 * 1024;
private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
public static async Task HandleAsync(WebSocket socket, CancellationToken cancellationToken)
{
Channel<string> outgoing = Channel.CreateUnbounded<string>(new UnboundedChannelOptions
{
SingleReader = true,
SingleWriter = false
});
MyHandler1 drawHandler = (sender, drawEvent) =>
{
r2warsStatic.r2w.sync_var = false;
outgoing.Writer.TryWrite(drawEvent.message);
};
using CancellationTokenSource connectionCancellation =
CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
CancellationToken connectionToken = connectionCancellation.Token;
r2warsStatic.r2w.Event_draw += drawHandler;
outgoing.Writer.TryWrite(r2warsStatic.torneo.GetStateJson());
try
{
Task receiveTask = ReceiveLoopAsync(socket, outgoing.Writer, connectionToken);
Task sendTask = SendLoopAsync(socket, outgoing.Reader, connectionToken);
await Task.WhenAny(receiveTask, sendTask);
connectionCancellation.Cancel();
outgoing.Writer.TryComplete();
try
{
await Task.WhenAll(receiveTask, sendTask);
}
catch (OperationCanceledException) when (connectionToken.IsCancellationRequested)
{
}
catch (WebSocketException)
{
// The peer disconnected without completing a close handshake.
}
}
finally
{
r2warsStatic.r2w.Event_draw -= drawHandler;
outgoing.Writer.TryComplete();
}
}
private static async Task ReceiveLoopAsync(
WebSocket socket,
ChannelWriter<string> outgoing,
CancellationToken cancellationToken)
{
byte[] buffer = new byte[4096];
while (socket.State == WebSocketState.Open)
{
using MemoryStream message = new MemoryStream();
WebSocketReceiveResult result;
do
{
result = await socket.ReceiveAsync(
new ArraySegment<byte>(buffer), cancellationToken);
if (result.MessageType == WebSocketMessageType.Close)
{
await socket.CloseOutputAsync(
WebSocketCloseStatus.NormalClosure,
"Closing",
CancellationToken.None);
return;
}
if (result.MessageType != WebSocketMessageType.Text)
{
await socket.CloseAsync(
WebSocketCloseStatus.InvalidMessageType,
"Only text commands are supported.",
cancellationToken);
return;
}
message.Write(buffer, 0, result.Count);
if (message.Length > MaxMessageSize)
{
await socket.CloseAsync(
WebSocketCloseStatus.MessageTooBig,
"Command is too large.",
cancellationToken);
return;
}
}
while (!result.EndOfMessage);
string response = Dispatch(Encoding.UTF8.GetString(message.ToArray()));
if (!string.IsNullOrEmpty(response))
outgoing.TryWrite(response);
}
}
private static async Task SendLoopAsync(
WebSocket socket,
ChannelReader<string> outgoing,
CancellationToken cancellationToken)
{
await foreach (string message in outgoing.ReadAllAsync(cancellationToken))
{
byte[] payload = Encoding.UTF8.GetBytes(message);
await socket.SendAsync(
new ArraySegment<byte>(payload),
WebSocketMessageType.Text,
true,
cancellationToken);
}
}
private static string Dispatch(string command)
{
if (command.TrimStart().StartsWith("{", StringComparison.Ordinal))
{
try
{
return DispatchJson(command);
}
catch (Exception exception)
{
return JsonSerializer.Serialize(new
{
type = "error",
message = exception.Message,
recoverable = true
}, JsonOptions);
}
}
switch (command)
{
case "cmd_state":
return r2warsStatic.torneo.GetStateJson();
case "cmd_prevlog":
return r2warsStatic.r2w.prevLog();
case "cmd_nextlog":
return r2warsStatic.r2w.nextLog();
case "cmd_load":
r2warsStatic.torneo.LoadTournamentPlayers();
break;
case "cmd_reset":
r2warsStatic.torneo.ResetTournament();
break;
case "cmd_run":
r2warsStatic.torneo.RunTournamentCombats();
break;
case "cmd_stop":
r2warsStatic.torneo.StopActualCombat();
break;
case "cmd_step":
case "cmd_next":
r2warsStatic.torneo.StepTournamentCombats();
break;
case "cmd_dbg4":
r2warsStatic.r2w.bStopAtRoundStart = false;
break;
case "cmd_dbg4si":
r2warsStatic.r2w.bStopAtRoundStart = true;
break;
case "cmd_dbg5":
r2warsStatic.r2w.bStopAtRoundEnd = false;
break;
case "cmd_dbg5si":
r2warsStatic.r2w.bStopAtRoundEnd = true;
break;
case "moreflow":
r2warsStatic.r2w.sync_var = true;
return "none";
case "arch_arm":
r2warsStatic.r2w.answer = "arm";
break;
case "arch_x86":
r2warsStatic.r2w.answer = "x86";
break;
}
return null;
}
private static string DispatchJson(string payload)
{
using JsonDocument document = JsonDocument.Parse(payload);
JsonElement root = document.RootElement;
string type = root.GetProperty("type").GetString() ?? "";
switch (type)
{
case "bots":
return JsonSerializer.Serialize(new
{
type = "bots",
warriors = r2warsStatic.torneo.GetWarriorSources()
}, JsonOptions);
case "assemble":
{
int requestId = root.GetProperty("requestId").GetInt32();
BrowserWarriorSource warrior = root.GetProperty("warrior")
.Deserialize<BrowserWarriorSource>(JsonOptions);
WarriorAssemblyResult result = WarriorCompiler.Assemble(warrior);
return JsonSerializer.Serialize(new
{
type = "assembly",
requestId,
ok = result.Ok,
bytes = Array.ConvertAll(result.Bytes, value => (int)value),
size = result.Size,
message = result.Message
}, JsonOptions);
}
case "load":
case "start":
{
BrowserWarriorSource[] warriors = root.GetProperty("warriors")
.Deserialize<BrowserWarriorSource[]>(JsonOptions) ?? Array.Empty<BrowserWarriorSource>();
r2warsStatic.torneo.LoadTournamentSources(warriors);
if (type == "start")
r2warsStatic.torneo.RunTournamentCombats();
return null;
}
default:
throw new InvalidOperationException("Unknown browser message type: " + type);
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

+87
View File
@@ -0,0 +1,87 @@
var e=()=>Array.from({length:1024},()=>``),t=()=>({workflow:`loading`,message:`Loading radare2 WebAssembly…`,player1:{name:`Player 1`,regs:``,code:``},player2:{name:`Player 2`,regs:``,code:``},memory:e(),console:`[r2wars wasm]`,status:`Loading`,scores:`No tournament loaded.`,completedCombats:0,totalCombats:0,activePlayer:-1,historyPosition:0,historyCount:0,canBrowseEarlier:!1,canBrowseLater:!1}),n=[[`.arm-16.`,{id:`arm-16`,arch:`arm`,bits:16}],[`.arm-32.`,{id:`arm-32`,arch:`arm`,bits:32}],[`.arm-64.`,{id:`arm-64`,arch:`arm`,bits:64}],[`.mips-32.`,{id:`mips-32`,arch:`mips`,bits:32}],[`.mips-64.`,{id:`mips-64`,arch:`mips`,bits:64}],[`.x86-32.`,{id:`x86-32`,arch:`x86`,bits:32}],[`.x86-64.`,{id:`x86-64`,arch:`x86`,bits:64}],[`.riscv-32.`,{id:`riscv-32`,arch:`riscv`,bits:32}],[`.riscv-64.`,{id:`riscv-64`,arch:`riscv`,bits:64}],[`.gb.`,{id:`gb`,arch:`gb`,bits:16}],[`.8051.`,{id:`8051`,arch:`8051`,bits:8,cpu:`8051-shared-code-xdata`}]];function r(e){let t=e.toLowerCase(),r=n.find(([e])=>t.includes(e));if(!r)throw Error(`${e}: architecture must be encoded in the filename, for example .x86-32.asm or .arm-32.asm`);return r[1]}function i(e){return e.map(e=>({...e}))}function a(e,t){let n=i(e);for(let e of t){let t=n.findIndex(t=>t.name.toLowerCase()===e.name.toLowerCase());t>=0?n[t]={...e}:n.push({...e})}return n}function o(e){let t=new Set(e.map(e=>e.name.toLowerCase())),n=1;for(;t.has(`new-warrior-${n}.x86-32.asm`);)n++;return{name:`new-warrior-${n}.x86-32.asm`,source:`start:
nop
jmp start
`}}function s(e){if(e.length<2)throw Error(`Add at least two bots before starting a tournament.`);let t=new Set;for(let n of e){let e=n.name.trim();if(!e.toLowerCase().endsWith(`.asm`))throw Error(`${e||`Unnamed bot`}: filename must end in .asm`);r(e);let i=e.toLowerCase();if(t.has(i))throw Error(`Duplicate bot filename: ${e}`);if(t.add(i),!n.source.trim())throw Error(`${e}: source is empty`)}}var c=null,l=0,u=null,d=null,f=!1,p=t(),m=!1,h=!1,g=[],_=-1,v=!1,y=`replace`,b=0,x=e=>{let t=document.getElementById(e);if(!t)throw Error(`Missing UI element #${e}`);return t};function S(e){if(!c||c.readyState!==WebSocket.OPEN)throw Error(`The .NET connection is not ready`);c.send(e.type===`command`?e.command:JSON.stringify(e))}function C(e){m&&(h=!0,S({type:`command`,command:e}),G())}function w(){document.title=`r2wars — .NET arena`;let e=document.createElement(`meta`);e.name=`description`,e.content=`Run multi-architecture r2wars tournaments with the native .NET and radare2 engine.`,document.head.append(e);let t=document.createElement(`style`);t.textContent=`
.connection.local { background:#d8e8ff; color:#174f85; }
.drop-active::after { content:'Drop .asm warriors to load them'; position:fixed; inset:18px; z-index:10; display:grid; place-items:center; border:4px dashed springgreen; background:rgba(0,0,0,.88); color:springgreen; font:700 1.5rem monospace; }
.wasm-note { color:#444; font-size:.72em; margin-right:auto; }
#report_download { margin-left:8px; position:absolute; right:100px; top:24px; width:auto; padding:7px 18px; }
.control-row { grid-template-columns:repeat(3,1fr); }
.bot-manager[hidden] { display:none; }
.bot-manager { position:fixed; inset:2%; z-index:20; display:grid; place-items:center; background:rgba(0,0,0,.84); border:3px solid #999; border-radius:7px; }
.bot-manager-panel { box-sizing:border-box; display:flex; flex-direction:column; width:min(1100px,96%); height:min(760px,94%); overflow:hidden; color:#111; background:#ddd; border:2px solid #eee; box-shadow:0 12px 42px #000; }
.bot-manager-header { display:flex; align-items:center; justify-content:space-between; gap:16px; padding:10px 14px; color:white; background:linear-gradient(90deg,#123b8d,#8b1717); }
.bot-manager-header h2 { margin:0; font-size:1.15rem; }
.bot-manager-header span { font-size:.78rem; }
.bot-manager-body { min-height:0; flex:1; display:grid; grid-template-columns:minmax(220px,30%) 1fr; gap:10px; padding:10px; }
.bot-sidebar,.bot-editor { min-height:0; display:flex; flex-direction:column; gap:8px; }
.bot-editor.no-selection > :not(.bot-editor-empty) { display:none; }
.bot-list { min-height:120px; flex:1; overflow:auto; padding:4px; background:#171717; border:1px inset #aaa; }
.bot-list button { margin-bottom:4px; padding:7px 8px; overflow:hidden; text-align:left; text-overflow:ellipsis; white-space:nowrap; color:#e8e8e8; background:#292929; border:1px solid #555; }
.bot-list button.selected { color:#111; background:#9ed1ff; border-color:#3275aa; font-weight:bold; }
.bot-sidebar-actions,.bot-manager-footer { display:flex; gap:8px; }
.bot-sidebar-actions button,.bot-manager-footer button { width:auto; padding:7px 14px; }
.bot-editor label { font-size:.8rem; font-weight:bold; }
.bot-editor input,.bot-editor textarea { box-sizing:border-box; width:100%; color:#d8ffd8; background:#111; border:1px inset #aaa; font:14px/1.4 Consolas,'Courier New',monospace; }
.bot-editor input { padding:7px; }
.bot-editor textarea { min-height:180px; flex:1; padding:10px; resize:none; tab-size:2; }
.bot-assembly { min-height:84px; max-height:150px; display:flex; flex-direction:column; gap:5px; overflow:auto; padding:7px; color:#ddd; background:#171717; border:1px inset #aaa; }
.bot-assembly-summary { display:flex; align-items:center; gap:7px; font-size:.78rem; }
.bot-assembly-summary strong { min-width:0; overflow-wrap:anywhere; }
.bot-compile-indicator { width:11px; height:11px; flex:0 0 11px; border-radius:50%; background:#777; box-shadow:0 0 5px #555; }
.bot-compile-indicator.pending { background:#e5b72f; box-shadow:0 0 6px #e5b72f; }
.bot-compile-indicator.valid { background:#39e75f; box-shadow:0 0 6px #39e75f; }
.bot-compile-indicator.invalid { background:#f04444; box-shadow:0 0 6px #f04444; }
.bot-assembly-size { margin-left:auto; color:#9ed1ff; white-space:nowrap; }
.bot-byte-array { min-height:38px; margin:0; overflow:auto; color:#b7e6ff; font:12px/1.35 Consolas,'Courier New',monospace; white-space:pre-wrap; word-break:break-all; }
.bot-editor-empty { display:grid; flex:1; place-items:center; color:#555; border:1px dashed #999; }
.bot-manager-footer { align-items:center; padding:9px 12px; border-top:1px solid #999; }
.bot-manager-status { min-height:1.2em; flex:1; color:#444; font-size:.78rem; }
.bot-manager-status.error { color:#8c1010; font-weight:bold; }
#bot_start { background:#d8f5de; border-color:#318244; font-weight:bold; }
@media (max-width: 900px), (orientation: portrait) {
.bot-manager { inset:0; border:0; }
.bot-manager-panel { height:100%; width:100%; }
.bot-manager-body { grid-template-columns:1fr; grid-template-rows:minmax(150px,32%) 1fr; }
.bot-manager-header span { display:none; }
}
`,document.head.append(t);let n=document.createElement(`input`);n.type=`file`,n.accept=`.asm,text/plain`,n.multiple=!0,n.hidden=!0,n.setAttribute(`aria-label`,`Choose warrior assembly files`),document.body.append(n);let r=document.querySelector(`.inspection-row`);if(r){let e=document.createElement(`span`);e.className=`wasm-note`,e.textContent=`Native engine · drop .asm files anywhere`,r.prepend(e)}let i=document.createElement(`button`);i.id=`cmd_bots`,i.textContent=`Bots`,i.title=`Add, remove, or edit bots for the next tournament`,document.querySelector(`.control-row`)?.append(i);let a=document.createElement(`div`);a.id=`bot_manager`,a.className=`bot-manager`,a.hidden=!0,a.setAttribute(`role`,`dialog`),a.setAttribute(`aria-modal`,`true`),a.setAttribute(`aria-labelledby`,`bot_manager_title`),a.innerHTML=`
<div class="bot-manager-panel">
<header class="bot-manager-header">
<h2 id="bot_manager_title">Bot manager</h2>
<span>Draft changes are loaded only when a new tournament starts</span>
</header>
<div class="bot-manager-body">
<aside class="bot-sidebar">
<strong id="bot_count">0 bots</strong>
<div id="bot_list" class="bot-list" role="listbox" aria-label="Loaded bots"></div>
<div class="bot-sidebar-actions">
<button id="bot_add" type="button">New bot</button>
<button id="bot_import" type="button">Import .asm</button>
</div>
</aside>
<section class="bot-editor">
<label for="bot_name">Filename and architecture</label>
<input id="bot_name" type="text" autocomplete="off" spellcheck="false" placeholder="name.x86-32.asm">
<label for="bot_source">Assembly source</label>
<textarea id="bot_source" spellcheck="false" aria-label="Bot assembly source"></textarea>
<div class="bot-assembly" aria-live="polite">
<div class="bot-assembly-summary">
<span id="bot_compile_indicator" class="bot-compile-indicator" aria-hidden="true"></span>
<strong id="bot_compile_status">Not checked</strong>
<span id="bot_assembly_size" class="bot-assembly-size">0 bytes</span>
</div>
<pre id="bot_byte_array" class="bot-byte-array">[]</pre>
</div>
<div class="bot-sidebar-actions">
<button id="bot_delete" type="button">Delete selected bot</button>
</div>
<div id="bot_editor_empty" class="bot-editor-empty" hidden>Select a bot to edit its source.</div>
</section>
</div>
<footer class="bot-manager-footer">
<span id="bot_manager_status" class="bot-manager-status" role="status"></span>
<button id="bot_close" type="button">Close</button>
<button id="bot_start" type="button">Start new tournament</button>
</footer>
</div>`,document.body.append(a);let o=document.createElement(`button`);return o.id=`report_download`,o.textContent=`Download report`,o.hidden=!0,x(`overlay`).append(o),o.addEventListener(`click`,re),n}var T=w();T.addEventListener(`change`,async()=>{if(T.files?.length){let e=await D(Array.from(T.files));g=y===`replace`?e:a(g,e);let t=e.at(-1)?.name.toLowerCase();_=t?g.findIndex(e=>e.name.toLowerCase()===t):-1,v=!0,j()}T.value=``}),x(`cmd_load`).addEventListener(`click`,()=>{y=`replace`,T.click()}),x(`cmd_bots`).addEventListener(`click`,j),x(`cmd_run`).addEventListener(`click`,()=>{p.workflow===`running`?C(`cmd_stop`):p.workflow===`paused`?C(`cmd_run`):A()}),x(`cmd_step`).addEventListener(`click`,()=>C(`cmd_step`)),x(`cmd_reset`).addEventListener(`click`,()=>{(p.workflow!==`running`&&p.workflow!==`paused`||window.confirm(`Reset this tournament? Current progress and scores will be cleared.`))&&ne()}),x(`cmd_scores`).addEventListener(`click`,X),x(`log_prev`).addEventListener(`click`,()=>C(`cmd_prevlog`)),x(`log_next`).addEventListener(`click`,()=>C(`cmd_nextlog`)),x(`score_close`).addEventListener(`click`,Q),x(`nowarriorsclose`).addEventListener(`click`,$),x(`bot_add`).addEventListener(`click`,N),x(`bot_import`).addEventListener(`click`,()=>{y=`merge`,T.click()}),x(`bot_delete`).addEventListener(`click`,P),x(`bot_close`).addEventListener(`click`,M),x(`bot_start`).addEventListener(`click`,A),x(`bot_name`).addEventListener(`input`,e=>{_<0||(g[_].name=e.currentTarget.value,v=!0,I(),R(),G(),z())}),x(`bot_source`).addEventListener(`input`,e=>{_<0||(g[_].source=e.currentTarget.value,v=!0,R(),z())}),x(`overlay`).addEventListener(`click`,e=>{e.target===x(`overlay`)&&Q()}),x(`bot_manager`).addEventListener(`click`,e=>{e.target===x(`bot_manager`)&&M()}),document.addEventListener(`keydown`,e=>{e.key===`Escape`&&(x(`bot_manager`).hidden?(Q(),$()):M())}),document.addEventListener(`dragover`,e=>{e.preventDefault(),p.workflow!==`running`&&document.body.classList.add(`drop-active`)}),document.addEventListener(`dragleave`,e=>{e.relatedTarget||document.body.classList.remove(`drop-active`)}),document.addEventListener(`drop`,async e=>{if(e.preventDefault(),document.body.classList.remove(`drop-active`),p.workflow===`running`)return;let t=Array.from(e.dataTransfer?.files??[]).filter(e=>e.name.toLowerCase().endsWith(`.asm`));if(t.length){let e=await D(t);g=a(g,e);let n=e.at(-1)?.name.toLowerCase();_=n?g.findIndex(e=>e.name.toLowerCase()===n):-1,v=!0,j()}});async function E(e){e.type===`ready`?(m=!0,x(`connection`).textContent=`.NET server`,x(`connection`).className=`connection local`,f?S({type:`command`,command:`cmd_state`}):(f=!0,await O())):e.type===`bots`?(u?.(e.warriors),u=null,d=null):e.type===`assembly`?B(e):e.type===`state`?(h=!1,p=ee(p,e.state),K()):e.recoverable?(h=!1,d?.(Error(e.message)),u=null,d=null,f&&(j(),R(e.message)),G()):V(e.message)}function ee(e,t){return{...e,...t,player1:{...e.player1,...t.player1},player2:{...e.player2,...t.player2},memory:t.memory??e.memory}}async function D(e){return Promise.all(e.map(async e=>({name:e.name,source:await e.text()})))}async function O(){try{g=i(await te()),_=g.length?0:-1,v=!1,S({type:`load`,warriors:i(g)})}catch(e){p.workflow=`idle`,p.message=`Choose at least two warrior files. Bundled examples could not be loaded: ${e instanceof Error?e.message:e}`,K()}}function te(){return new Promise((e,t)=>{u=e,d=t,c?.send(JSON.stringify({type:`bots`})),window.setTimeout(()=>{u===e&&(u=null,d=null,t(Error(`Timed out while loading bots from the .NET server`)))},5e3)})}function k(){return g.map(e=>({name:e.name.trim(),source:e.source}))}function A(){try{let e=k();s(e),g=i(e),v=!1,h=!0,M(),S({type:`start`,warriors:i(g)}),G()}catch(e){j(),R(e instanceof Error?e.message:String(e))}}function ne(){try{let e=k();s(e),g=i(e),v=!1,h=!0,S({type:`load`,warriors:i(g)}),G()}catch(e){j(),R(e instanceof Error?e.message:String(e))}}function j(){if(!m||p.workflow===`running`)return;let e=x(`bot_manager`);e.hidden=!1,L(),_>=0?x(`bot_name`).focus():x(`bot_add`).focus()}function M(){x(`bot_manager`).hidden=!0,x(`cmd_bots`).focus({preventScroll:!0})}function N(){g.push(o(g)),_=g.length-1,v=!0,L();let e=x(`bot_name`);e.focus(),e.select()}function P(){if(_<0)return;let e=g[_].name||`this bot`;window.confirm(`Delete ${e} from the next tournament?`)&&(g.splice(_,1),_=g.length?Math.min(_,g.length-1):-1,v=!0,L())}function F(e){_=e,L(),x(`bot_source`).focus()}function I(){let e=x(`bot_list`);e.replaceChildren(),g.forEach((t,n)=>{let r=document.createElement(`button`);r.type=`button`,r.textContent=t.name||`Unnamed bot`,r.title=t.name||`Unnamed bot`,r.classList.toggle(`selected`,n===_),r.setAttribute(`role`,`option`),r.setAttribute(`aria-selected`,String(n===_)),r.addEventListener(`click`,()=>F(n)),e.append(r)}),x(`bot_count`).textContent=`${g.length} bot${g.length===1?``:`s`}`,x(`cmd_bots`).textContent=`Bots (${g.length})`}function L(){_>=g.length&&(_=g.length-1),I();let e=_>=0?g[_]:void 0;document.querySelector(`Line truncated
+722
View File
@@ -0,0 +1,722 @@
<!doctype html>
<html lang="en" data-r2wars-engine="dotnet">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Run multi-architecture r2wars tournaments with radare2.">
<title>r2wars</title>
<style>
button {
min-width: 10px;
}
button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
.connection {
border-radius: 10px;
color: #333;
font-size: 0.78em;
padding: 2px 7px;
}
.connection.connected {
background: #c7f4d0;
color: #145b23;
}
.connection.connecting {
background: #fff2b7;
}
.connection.disconnected {
background: #ffd0d0;
color: #7b1111;
}
table {
}
button {
width: 100%;
}
.addr {
color: white;
text-align: center;
background-color: black;
font-weight: bold;
width: 6em;
}
.div1 {
position: absolute;
top: 0px;
left: 0px;
width: 30%;
height: 100%;
overflow-x: hidden;
}
.divM3 {
position: fixed;
bottom: 0px;
background-color: #e0e0e0;
left: 30%;
right: 30%;
width: 40%;
height: 16em;
overflow: hidden;
}
.divM2 {
position: fixed;
bottom: 16em;
background-color: #e0e0e0;
left: 30%;
right: 30%;
width: 40%;
height: 132px;
box-sizing: border-box;
border: 1px solid #a0a0a0;
padding: 7px;
overflow: hidden;
}
.status-strip, .inspection-row {
align-items: center;
display: flex;
gap: 7px;
}
.status-strip {
justify-content: space-between;
}
.workflow-badge {
background: #d2d2d2;
border-radius: 10px;
font-size: 0.78em;
font-weight: bold;
padding: 2px 8px;
text-transform: uppercase;
white-space: nowrap;
}
.workflow-badge.ready { background: #d5e9ff; color: #174f85; }
.workflow-badge.running { background: #c7f4d0; color: #145b23; }
.workflow-badge.paused { background: #fff2b7; color: #705600; }
.workflow-badge.finished { background: #d9ccff; color: #41257c; }
.progress {
flex: 1;
font-size: 0.78em;
font-weight: bold;
}
.workflow-message {
height: 30px;
line-height: 15px;
margin: 5px 1px;
overflow: hidden;
}
.stage-notice {
background: rgba(18, 18, 18, 0.92);
border: 2px solid #aaa;
border-radius: 6px;
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.55);
color: white;
left: 8%;
padding: 18px 22px;
position: absolute;
right: 8%;
text-align: center;
top: 18%;
z-index: 1;
}
.stage-notice[hidden] { display: none; }
.stage-notice strong {
color: springgreen;
display: block;
font-size: 1.55em;
margin-bottom: 8px;
}
.stage-notice.ready strong { color: #8fc7ff; }
.stage-notice.finished strong { color: #c9b4ff; }
.control-row {
display: grid;
gap: 5px;
grid-template-columns: 1.3fr 1.4fr 0.8fr 0.8fr 0.8fr;
}
.control-row button, .inspection-row button {
background: #f3f3f3;
border: 1px solid #777;
border-radius: 3px;
min-height: 25px;
}
.control-row button.primary {
background: #d8f5de;
border-color: #318244;
font-weight: bold;
}
.control-row button.primary.pause {
background: #fff0bd;
border-color: #9a761c;
}
.inspection-row {
font-size: 0.75em;
justify-content: flex-end;
margin-top: 5px;
}
.inspection-row button {
max-width: 92px;
}
.divM {
position: absolute;
top: 0px;
left: 30%;
right: 30%;
height: 100%;
width: 40%;
overflow-x: scroll;
}
.div2 {
position: absolute;
top: 0px;
right: 0px;
width: 30%;
height: 100%;
overflow-x: hidden;
}
.memory {
overflow-y: hidden;
height: 100%;
background-color: #303030;
}
.box {
width: 1em;
height: 1em;
text-align: center;
color: white;
background-color: #a0a0a0;
font-weight: bold;
}
.console {
height: 14.5em;
background-color: black;
color: white;
font-family: Courier New;
font-size: 14px;
font-weight: bold;
white-space: pre;
overflow-y: scroll;
overflow-x: scroll;
}
.console1 {
height: 238px;
background-color: black;
width: 100%;
color: white;
font-family: Courier New;
font-size: 15px;
font-weight: bold;
white-space: pre;
overflow-y: hidden;
overflow-x: hidden;
}
.console2 {
height: 100%;
background-color: black;
color: springgreen;
font-family: Courier New;
font-size: 13px;
font-weight: bold;
width: 100%;
white-space: pre;
overflow-x: hidden;
overflow-y: hidden;
}
.s {
background-color: green;
color: black;
font-family: Courier New;
font-weight: bold;
white-space: pre;
}
body {
overflow: hidden;
background-color: #909090;
}
td {
font-family: Courier New;
border: 1px solid #a0a0a0;
color: black;
}
button {
min-width: 1px;
background-color: inherit;
}
div {
font-family: Courier New;
}
tr {
background-color: #e0e0e0;
}
.player1 {
background-color: blue;
width: 100%;
color: white;
font-weight: bold;
font-size: 2em;
font-family: Consolas, Courier New;
overflow-x: hidden;
text-align: left;
padding-left: 2em;
}
.player2 {
color: white;
width: 100%;
background-color: red;
font-weight: bold;
font-size: 2em;
font-family: Consolas, Courier New;
overflow-x: hidden;
text-align: left;
padding-left: 0em;
}
.active-dot {
display: inline-block;
width: 0.8em;
height: 0.8em;
margin: 0 0.5em;
border: 2px solid white;
border-radius: 50%;
background-color: #4b4b4b;
vertical-align: middle;
}
.active-dot.active {
background-color: #39e75f;
box-shadow: 0 0 0.5em #39e75f;
animation: active-pulse 0.8s ease-in-out infinite alternate;
}
@keyframes active-pulse {
from { transform: scale(0.85); }
to { transform: scale(1.15); }
}
.memtable {
font-size: 10px;
width: 100%;
}
.overlay {
display: none;
top: 1%;
width: 90%;
right: 5%;
bottom: 1%;
background-color: rgba(0, 0, 0, 0.9);
z-index: 2;
position: absolute;
border-radius: 6px;
border: 3px solid #a0a0a0;
}
.text {
font-weight: bold;
margin: 24px 80px 12px 30px;
font-size: 40px;
color: springgreen;
}
.text1 {
font-weight: bold;
font-size: 1.4em;
color: white;
white-space: pre;
margin: 20px 30px;
max-height: calc(100% - 130px);
overflow: auto;
}
.overlay-close {
background: #e5e5e5;
border: 1px solid #888;
border-radius: 3px;
padding: 7px 18px;
position: absolute;
right: 24px;
top: 24px;
width: auto;
}
.win98 {
display: none;
top: 30%;
left: 30%;
right: 30%;
z-index: 3;
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: none;
font-size: 11px;
font-family: Tahoma, Verdana;
color: #070707;
position: absolute;
margin: 0 auto;
background: #bfbfbf;
border: 1px solid;
border-top-color: #dfdfdf;
border-left-color: #dfdfdf;
border-right-color: #808080;
border-bottom-color: #808080;
box-shadow: 1px 1px 0 0 #000;
width: 400px;
cursor: default;
}
.win98 .content {
padding: 7px 10px;
font-size: 16px;
}
.win98 .header {
margin: 2px 2px 0;
padding: 1px 2px;
color: #fff;
background: -webkit-linear-gradient(left, blue, red);
background: linear-gradient(to right, blue, red);
font-weight: bold;
font-size: 16px;
line-height: 16px;
}
.legend1 {
position: absolute;
top: 10px;
z-index: 2;
background-color: black;
left: 10px;
font-weight: bold;
text-align: center;
}
.legend2 {
position: absolute;
top: 10px;
z-index: 2;
background-color: black;
right: 10px;
font-weight: bold;
text-align: left;
}
.legend {
font-weight: bold;
text-align: center;
width: 10px;
max-width: 10px;
height: 1em;
}
.win98 button {
-webkit-font-smoothing: none;
-moz-osx-font-smoothing: none;
font-size: 11px;
font-family: Tahoma, Verdana;
color: #070707;
background: #bfbfbf;
border: 1px solid;
border-top-color: #dfdfdf;
border-left-color: #dfdfdf;
border-right-color: #808080;
border-bottom-color: #808080;
box-shadow: 1px 1px 0 0 #000;
text-align: center;
outline: none;
padding: 4px;
cursor: default;
font-size: 16px;
}
.win98 button:enabled {
color: #070707;
}
.win98 button:disabled {
color: #818181;
text-shadow: 1px 1px #fff;
}
.win98 button:active:enabled {
box-shadow: 1px 1px 0 0 #000 inset;
border-top-color: #808080;
border-left-color: #808080;
border-right-color: #dfdfdf;
border-bottom-color: #dfdfdf;
}
/* On narrow or portrait screens, keep the arena visible before the code. */
@media (max-width: 900px), (orientation: portrait) {
body {
margin: 0;
overflow: auto;
}
.div1, .div2, .divM, .divM2, .divM3 {
box-sizing: border-box;
left: auto;
position: relative;
right: auto;
top: auto;
width: 100%;
}
.div1, .div2 {
height: 180px;
min-height: 0;
overflow: hidden !important;
}
.div1 table, .div2 table {
height: 100% !important;
table-layout: fixed;
}
.player1, .player2 {
box-sizing: border-box;
font-size: 1.1em;
line-height: 1.5;
overflow: hidden;
padding-left: 0.5em;
text-overflow: ellipsis;
white-space: nowrap;
}
.active-dot {
height: 0.6em;
margin: 0 0.35em;
width: 0.6em;
}
.console1 {
box-sizing: border-box;
font-size: 12px;
height: 44px;
overflow: auto;
}
.console2 {
box-sizing: border-box;
font-size: 11px;
height: 94px;
line-height: 1.2;
min-height: 0;
overflow: auto;
}
.divM {
height: min(440px, 115vw);
min-height: 0;
overflow: auto;
}
.divM table {
height: 100% !important;
table-layout: fixed;
}
.memory {
min-width: 0;
}
.memtable {
font-size: 9px;
table-layout: fixed;
}
.addr {
width: 4em;
}
.box {
height: 0.9em;
padding: 0;
width: auto;
}
.divM2 {
bottom: auto;
min-height: 165px;
}
.divM3 {
bottom: auto;
height: 180px;
}
.control-row {
grid-template-columns: repeat(3, 1fr);
}
.legend1, .legend2 {
display: none;
}
}
</style>
</head>
<body>
<div id="overlay" class="overlay" role="dialog" aria-modal="true" aria-labelledby="score_title">
<div id="score_title" class="text">Tournament scores</div>
<button id="score_close" class="overlay-close">Close</button>
<pre id="scores" class="text1"></pre>
</div>
<div id="nowarriorsdlg" class="win98" role="dialog" aria-modal="true" aria-labelledby="warriors-title">
<div class="header">
<span id="warriors-title">Warriors not found</span>
</div>
<div class="content">
<center>
<h3>Add at least two .asm warrior files to the warriors directory, then load again.</h3>
<button id="nowarriorsclose">Close</button>
</center>
</div>
</div>
<div class="legend1">
<table>
<tbody>
<tr>
<td class="legend" style="background-color:aqua">R</td>
<td class="legend" style="background-color:violet">W</td>
</tr>
</tbody>
</table>
</div>
<div class="div1" style="overflow-y:hidden;">
<table style="height:100%;width:100%">
<tbody>
<tr>
<td class="player1"><span id="active1" class="active-dot" aria-label="Player 1 is waiting"></span><span id="player1">Player1</span></td>
</tr>
<tr style="height:100%">
<td valign="top" style="overflow-x:hidden;overflow-y:hidden">
<div class="console1" id="regs1"></div>
<div style="border: 1px solid #a0a0a0"></div>
<div class="console2" id="code1"></div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="divM" style="overflow-x:hidden">
<div id="stage_notice" class="stage-notice idle">
<strong id="stage_title">No tournament loaded</strong>
<span id="stage_detail">Load warriors to begin.</span>
</div>
<center class="">
<table style="height:100%;overflow-x:scroll;width:100%">
<tbody>
<tr style="height:100%">
<td valign="top"><div class="memory" id="memory"></div></td>
</tr>
</tbody>
</table>
</center>
</div>
<div class="divM2">
<div class="status-strip">
<span id="workflow_badge" class="workflow-badge idle">idle</span>
<span id="progress" class="progress">0 / 0 battles</span>
<span id="connection" class="connection connecting" role="status">Connecting…</span>
</div>
<div id="workflow_message" class="workflow-message">Load warriors to begin.</div>
<div class="control-row">
<button id="cmd_load" title="Scan the warriors directory for .asm files">Load warriors</button>
<button id="cmd_run" class="primary" title="Start or pause continuous tournament play">Start tournament</button>
<button id="cmd_step" title="Advance exactly one engine cycle while paused">Step</button>
<button id="cmd_scores" title="Show current standings">Scores</button>
<button id="cmd_reset" title="Clear progress and scores for the loaded warriors">Reset</button>
</div>
<div class="inspection-row">
<span>Execution history (paused):</span>
<button id="log_prev" title="Show the earlier recorded state for both warriors">Earlier state</button>
<button id="log_next" title="Show the later recorded state for both warriors">Later state</button>
</div>
</div>
<div class="divM3">
<center class="">
<table style="width:100%">
<tbody>
<tr style="height:100%">
<td style="height:100%">
<div id="console" class="console"></div>
</td>
</tr>
<tr style="height:100%">
<td id="status">Idle</td>
</tr>
</tbody>
</table>
</center>
</div>
<div class="legend2">
<table>
<tbody>
<tr>
<td class="legend" style="background-color:yellow">R</td>
<td class="legend" style="background-color:orange">W</td>
</tr>
</tbody>
</table>
</div>
<div class="div2" style="overflow-y:hidden">
<table style="height:100%;width:100%">
<tbody>
<tr>
<td class="player2"><span id="active2" class="active-dot" aria-label="Player 2 is waiting"></span><span id="player2">Player2</span></td>
</tr>
<tr style="height:100%">
<td valign="top" style="overflow-x:hidden;overflow-y:hidden" height="100%" colspan="3">
<div class="console1" id="regs2"></div>
<div style="border: 1px solid #a0a0a0"></div>
<div class="console2" id="code2"></div>
</td>
</tr>
</tbody>
</table>
</div>
<script type="module" src="/assets/r2wars-ui.js"></script>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
mov dptr, #kill
loop:
inc dptr
inc dptr
inc dptr
inc a
movx @dptr, a
sjmp loop
kill:
@@ -0,0 +1,18 @@
pack:
; mov edi, 0xcccccccc
; mov esi, 0xcccccccc
; mov ebp, 0xcccccccc
mov ebx, 0x00000400
mov edx, 0x6060dc89
mov ecx, 0x60606060
mov eax, 0xf9eb6060
unpack:
mov esp, 0x20
pushad
add esp, 0x14 ; if shorter
jmp esp
loop:
inc eax
jmp loop
@@ -0,0 +1,19 @@
call init
init:
pop esp
add esp, 0x26
mov dword [eax], esp ; esp saved @0x0
sub esp, 0x20
save:
popad
jmp restore
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
restore:
mov esp, dword [0x0]
add esp, 0x20
xor esi, esi
mov dword [esi], esp
pushad
@@ -0,0 +1,22 @@
# Anisse Astier
.arch arm
.bits 32
.hex 0c008fe2
.hex fe7fb0e8
.hex 020ca0e3
.hex fe7f80e8
.hex 81ffa0e3
.hex 3f0e00e2
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex 0600a0e8
.hex f3ffffea
.hex cccccccc
.hex cccccccc
@@ -0,0 +1,12 @@
; when i say jump -- you say how high
mov eax, 0xfeebfeeb; feebfeeb
mov ebx, eax
mov ecx, eax
mov edx, eax
mov ebp, eax
mov edi, eax
mov esp, 0x3fc
mov esi, 0x3fd
mov [esi], 0xe6ff60
jmp esi
@@ -0,0 +1,18 @@
sub x20, x20, 16;
movk x21, 0x1ff;
bl start;
start:
movk x22, 0x8a;
strb w22, [x30, 23]; // patch ORR -> AND
ldp x0, x1, [x30, 16]; // copy
ldp x2, x3, [x30, 32]; // copy
add x20, x20, 32;
orr x20, x20, x21; // becomes AND
stp x0, x1, [x20, 120]; // stomp
stp x0, x1, [x20, 480]; // stomp
stp x2, x3, [x20, 496]; // stomp
stp x0, x1, [x20, 0]; // paste
stp x2, x3, [x20, 16]; // paste
br x20;
@@ -0,0 +1,20 @@
mov ebx, 0x69696969
mov ecx, ebx
mov edx, 0x400
mov edi, 0xd439c401
mov esi, 0x60e04f0f
mov ebp, 0xe4ff6060
mov esp, 0x215
pushad
mov esp, 0x25
pushad
mov esp, 0x3f9
pushad
mov esp, 0x310
pushad
pushad
mov eax, 0xB9
jmp esp
@@ -0,0 +1,11 @@
; kaploombaa
.arch x86
.bits 32
mov esp, 0x70;
mov eax, 0x00008000;
mov ebx, 0x0003ffff;
mov edi, 0x000070bc;
mov esi, 0x21c70100;
mov ebp, 0xe4ff60df;
pushal;
jmp esp;
@@ -0,0 +1,24 @@
.bits 32
.arch arm
.hex 3f6e
.hex a0e3
.hex 0620
.hex 00e3
.hex 5121
.hex 4ee3
.hex 0030
.hex 01e3
.hex a031
.hex 48e3
.hex 3c40
.hex 00e3
.hex a148
.hex 4ee3
.hex 0f50
.hex 0fe3
.hex 4152
.hex 4ee3
.hex 0010
.hex 8fe2
.hex 3c00
.hex a1e8
@@ -0,0 +1,490 @@
; Warrior X86 32 bits by goyo.
; Despues del RevientaViejas (r2con2018), viene: 'GORDASCO'
; bot para r2wars (r2con2020)
; Básicamente un replicator con problemas de peso
.bits 32
Main:
CALL Boot
Boot:
POP ESI
JMP replicator
# Esto para engordar el binario a 512 bytes y reducir el area de busqueda inicial del otro bot a 512.
# Si es rápido podría encontrar al otro antes de que se mueva si es que se mueve.
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
replicator:
CLD
MOV BX,0x3d7 ; memory top
MOV EDI,ESI
ADD SI,461 ; offset Payload - offset Main
MOV EAX,ESI
ADD EDI,40 ; only for 1st replication
MOV [EDX],EAX ; Por si alguien se esconde en 0x0 o en 0x3ff y le pillo..
MOV [EBX+36],EAX
Payload:
MOV ESI,EAX ; payload start
MOV CL,0x0A ; loop rep // attack // copy to the last .byte 0xcc
SUB EDI,40+40+3 ; separation ( 40 from last movsd + 40 from new movsd + 3 extra)
JNC Nocheck ; check limits
MOV EDI,EBX
Nocheck:
MOV EAX,EDI
REP MOVSD ; replicator
JMP EAX
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
@@ -0,0 +1,38 @@
; r2wars warrior by zutle
; >> So you want to play the pusha game? :D
;
; The logic below generates the following code:
;
;
;payload:
; test sp, sp
; jnz replicate
; mov sp, 0x400
;replicate:
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; mov [esp + 0xc], ecx
; mov eax, esp
; jmp eax
call start
start:
pop esp
and esp, 0xffffff00
add esp, 0x20
mov edx, 0xe0ffe089
mov ebx, 0x0c244c89
mov ecx, 0x60606060
mov ebp, 0x60606060
mov esi, 0x0400bc66
mov edi, 0x0475e485
pushal
mov [esp + 0xc], ecx
mov eax, esp
jmp eax
@@ -0,0 +1,29 @@
call get_eip
get_eip:
pop esp
qq:
mov [esp+0x30], esp
pushad
pushad
pushad
popad
popad
popad
add esp, ecx
dec ecx
cmp esp, 0x80
ja qq
mov esp, 0x3a0
jmp qq
@@ -0,0 +1,33 @@
; her isimizde hayirlisi olsun
; pushad loopunu 0x14 civarına unpack ettikten sonra
; oraya ziplayip 0x400'den geriye pushad yapmaya baslar
; v3: a longer pushad init
pack:
; mov edi, 0xcccccccc
; mov esi, 0xcccccccc
; mov ebp, 0xcccccccc
mov ebx, 0x00000400
mov edx, 0x6060dc89
mov ecx, 0x60606060
mov eax, 0xf6eb6060
unpack:
mov esp, 0x220
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
add esp, 0x14 ; if shorter, tune this
jmp esp
@@ -0,0 +1,19 @@
call init
init:
pop esp
add esp, 0x26
mov dword [eax], esp ; esp saved @0x0
sub esp, 0x20
save:
popad
jmp restore
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
restore:
mov esp, dword [0x0]
add esp, 0x20
xor esi, esi
mov dword [esi], esp
pushad
@@ -0,0 +1,15 @@
mov eax, 0xc3c3c3c3
mov ebx, 1024
mov edx, 0xa0
mov ebp, 0xe4ff6060
mov esi, 0x606060e3
mov edi, 0x420fd439
call pwn
pwn:
pop esp
sub esp,4
pushad
mov esp, 0x340
pushad
jmp esp
@@ -0,0 +1,22 @@
# Anisse Astier
.arch arm
.bits 32
.hex 0c008fe2
.hex fe7fb0e8
.hex 020ca0e3
.hex fe7f80e8
.hex 81ffa0e3
.hex 3f0e00e2
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex fe7fa0e8
.hex 0600a0e8
.hex f3ffffea
.hex cccccccc
.hex cccccccc
@@ -0,0 +1,23 @@
; when i say jump -- you say how high
mov eax, 0xffffffff
mov ecx, eax
mov edx, eax
mov ebx, eax
mov ebp, eax
mov esi, eax
check:
mov edi, 0x000
cmp [edi], 0
jne planb
mov esp, 0x400
inc edi
mov [edi], 0xe7ff6060
jmp edi
planb:
mov edi, 0x3fb
mov [edi], 0xe7ff6060
mov esp, 0x3fa
jmp edi
@@ -0,0 +1,18 @@
sub x20, x20, 16;
movk x21, 0x1ff;
bl start;
start:
movk x22, 0x8a;
strb w22, [x30, 23]; // patch ORR -> AND
ldp x0, x1, [x30, 16]; // copy
ldp x2, x3, [x30, 32]; // copy
add x20, x20, 32;
orr x20, x20, x21; // becomes AND
stp x0, x1, [x20, 120]; // stomp
stp x0, x1, [x20, 480]; // stomp
stp x2, x3, [x20, 496]; // stomp
stp x0, x1, [x20, 0]; // paste
stp x2, x3, [x20, 16]; // paste
br x20;
@@ -0,0 +1,20 @@
mov ebx, 0x69696969
mov ecx, ebx
mov edx, 0x400
mov edi, 0xd439c401
mov esi, 0x60e04f0f
mov ebp, 0xe4ff6060
mov esp, 0x215
pushad
mov esp, 0x25
pushad
mov esp, 0x3f9
pushad
mov esp, 0x310
pushad
pushad
mov eax, 0xB9
jmp esp
@@ -0,0 +1,11 @@
; kaploombaa
.arch x86
.bits 32
mov esp, 0x70;
mov eax, 0x00008000;
mov ebx, 0x0003ffff;
mov edi, 0x000070bc;
mov esi, 0x21c70100;
mov ebp, 0xe4ff60df;
pushal;
jmp esp;
@@ -0,0 +1,21 @@
;.arch arm
.bits 32
.hex 00D04FE2 ; SUB SP,R15,0x00
.hex FF5FBDE8 ; POP {R0-R12,R14}
.hex 050D5DE3 ; r13 CMP SP,0x140
.hex FFFF2DA9 ; r14 PUSHGE {R0-15}
.hex FFFF2DA9 ; r12 PUSHGE
.hex FFFF2DA9 ; r12 PUSHGE
.hex FFFF2DA9 ; r11 PUSHGE
.hex FFFF2DA9 ; r10 PUSHGE
.hex 01DBA0D3 ; r9 orrle sp,r14,sp
.hex 0DF0A0C1 ; r8 MOVGT R15,SP #jump if SP>=0
.hex 24F05FE2 ; r6 SUBS R15,R15,0x24
.hex 11111111 ; r5
.hex 22222222 ; r4
.hex cccccccc ; r3
.hex 44444444 ; r2
.hex 00040000 ; r1
@@ -0,0 +1,490 @@
; Warrior X86 32 bits by goyo.
; Despues del RevientaViejas (r2con2018), viene: 'GORDASCO'
; bot para r2wars (r2con2020)
; Básicamente un replicator con problemas de peso
.bits 32
Main:
CALL Boot
Boot:
POP ESI
JMP replicator
# Esto para engordar el binario a 512 bytes y reducir el area de busqueda inicial del otro bot a 512.
# Si es rápido podría encontrar al otro antes de que se mueva si es que se mueve.
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
replicator:
CLD
MOV BX,0x3d7 ; memory top
MOV EDI,ESI
ADD SI,461 ; offset Payload - offset Main
MOV EAX,ESI
ADD EDI,40 ; only for 1st replication
MOV [EDX],EAX ; Por si alguien se esconde en 0x0 o en 0x3ff y le pillo..
MOV [EBX+36],EAX
Payload:
MOV ESI,EAX ; payload start
MOV CL,0x0A ; loop rep // attack // copy to the last .byte 0xcc
SUB EDI,40+40+3 ; separation ( 40 from last movsd + 40 from new movsd + 3 extra)
JNC Nocheck ; check limits
MOV EDI,EBX
Nocheck:
MOV EAX,EDI
REP MOVSD ; replicator
JMP EAX
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
@@ -0,0 +1,19 @@
lea rsp, [0x25]
mov rbx, qword[rsp]
mov rcx, qword[rsp+8]
mov r10, 0x25f
mov r11, 0x3f0
mov r12, 0x10
add rsp, r10
and rsp, r11
add rsp, r12
push rcx
push rbx
jmp rsp
nop
nop
nop
nop
nop
nop
@@ -0,0 +1,38 @@
; r2wars warrior by zutle
; >> So you want to play the pusha game? :D
;
; The logic below generates the following code:
;
;
;payload:
; test sp, sp
; jnz replicate
; mov sp, 0x400
;replicate:
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; mov [esp + 0xc], ecx
; mov eax, esp
; jmp eax
call start
start:
pop esp
and esp, 0xffffff00
add esp, 0x20
mov edx, 0xe0ffe089
mov ebx, 0x0c244c89
mov ecx, 0x60606060
mov ebp, 0x60606060
mov esi, 0x0400bc66
mov edi, 0x0475e485
pushal
mov [esp + 0xc], ecx
mov eax, esp
jmp eax
@@ -0,0 +1,18 @@
; This bot sucks but I wamted to make something
mov esp, 0x3de
mov edx, 0xdead
mov ebx, 0xdead
mov ecx, 0xdead
jmp loop
hijack:
jmp eax
loop:
inc al
cmp eax, 0x3de
jle continue
xor eax, eax
continue:
cmp [eax], 0x00
jne hijack
pushal
jmp loop
@@ -0,0 +1,19 @@
call get_eip
get_eip:
pop esp
sub ecx, 0x20
dec eax
qq:
pushad
pushad
pushad
add esp, ecx
dec ecx
cmp esp, 0x80
ja qq
mov esp, 0x3a0
jmp qq
@@ -0,0 +1,33 @@
; her isimizde hayirlisi olsun
; pushad loopunu 0x14 civarına unpack ettikten sonra
; oraya ziplayip 0x400'den geriye pushad yapmaya baslar
; v3: a longer pushad init
pack:
; mov edi, 0xcccccccc
; mov esi, 0xcccccccc
; mov ebp, 0xcccccccc
mov ebx, 0x00000400
mov edx, 0x6060dc89
mov ecx, 0x60606060
mov eax, 0xf6eb6060
unpack:
mov esp, 0x220
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
pushad
add esp, 0x14 ; if shorter, tune this
jmp esp
@@ -0,0 +1,19 @@
call init
init:
pop esp
add esp, 0x26
mov dword [eax], esp ; esp saved @0x0
sub esp, 0x20
save:
popad
jmp restore
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
restore:
mov esp, dword [0x0]
add esp, 0x20
xor esi, esi
mov dword [esi], esp
pushad
@@ -0,0 +1,15 @@
mov eax, 0xc3c3c3c3
mov ebx, 1024
mov edx, 0xa0
mov ebp, 0xe4ff6060
mov esi, 0x606060e3
mov edi, 0x420fd439
call pwn
pwn:
pop esp
sub esp,4
pushad
mov esp, 0x340
pushad
jmp esp
@@ -0,0 +1,25 @@
# Anisse Astier
.arch arm
.bits 32
.hex 18d08fe2
.hex ff5fbde8
.hex 34d0b0e3
.hex ff07ade8
.hex f00fade8
.hex 0f005ee1
.hex 80d0a043
.hex 44f0a043
.hex 3fde0d42
.hex ff1fad48
.hex ff07ad48
.hex f00fad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ecffff4a
.hex 0100005f
.hex ccc3ccc3
@@ -0,0 +1,17 @@
; when i say jump -- you say how high
mov eax, 0xffffffff
mov ecx, eax
mov edx, eax
mov ebx, eax
mov ebp, eax
mov esi, eax
mov edi, 0x000
mov esp, 0x400
mov [edi], 0x20fc8360
mov [edi+4], 0xff600374
mov [edi+8], 0x0400bce7
mov [edi+12], 0xe7ff0000
;mov [edi], 0xe7ff6060
jmp edi
@@ -0,0 +1,18 @@
sub x20, x20, 16;
movk x21, 0x1ff;
bl start;
start:
movk x22, 0x8a;
strb w22, [x30, 23]; // patch ORR -> AND
ldp x0, x1, [x30, 16]; // copy
ldp x2, x3, [x30, 32]; // copy
add x20, x20, 32;
orr x20, x20, x21; // becomes AND
stp x0, x1, [x20, 120]; // stomp
stp x0, x1, [x20, 480]; // stomp
stp x2, x3, [x20, 496]; // stomp
stp x0, x1, [x20, 0]; // paste
stp x2, x3, [x20, 16]; // paste
br x20;
@@ -0,0 +1,165 @@
call init
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
init:
mov eax, 0x340
mov ebx, 0xc3c3c3c3
mov ecx, ebx ; trash
mov edx, 0x400 ; end of arena
mov edi, 0xd439c401
mov esi, 0x60e04f0f
mov ebp, 0xe4ff6060
call yolo_1
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
yolo_1:
mov esp, 0x210
pushad
mov esp, 0x66
pushad
mov esp, 0x3f9
pushad
call yolo_2
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
yolo_2:
mov esp, eax ; relocate to `eax`
pushad
pushad
mov eax, 0x99 ; first address after reloc
jmp esp
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
@@ -0,0 +1,11 @@
; kaploombaa
.arch x86
.bits 32
mov eax, 0x00004000
mov ebx, 0x0003fcff
mov edi, 0x000070bc
mov esi, 0x21c70100
mov ebp, 0xe4ff60df
mov esp, 0x40
pushal
jmp esp
@@ -0,0 +1,30 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; bot for r2wars :: r2con2020 :: ;;
; _goyo_ ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;.arch arm
.bits 32
.hex 00D04FE2 ; SUB SP,R15,0x00
.hex FF5FBDE8 ; POP {R0-R12,R14}
sp_top:
.hex 050D5DE3 ; r0 CMP SP,0x140
top_from_subs:
.hex FFFF2DA9 ; r1 PUSHGE {R0-R15}
.hex FFFF2DA9 ; r2 PUSHGE {R0-R15}
.hex FFFF2DA9 ; r3 PUSHGE {R0-R15}
.hex FFFF2DA9 ; r4 PUSHGE {R0-R15}
.hex FFFF2DA9 ; r5 PUSHGE {R0-R15}
.hex 01DBA0D3 ; r6 MOVLE SP,0x400 ; time to go, sp low value
.hex 0DF0A0C1 ; r7 MOVGT R15,SP ; if SP>0x140
.hex FFFF2DE9 ; r8 PUSH {R0-R15} ; hole starting from 0x400
.hex 28F05FE2 ; r9 SUBS R15,R15,0x28 ; clear flag for pushge
.hex FFFFFFFF ; r10
.hex cccccccc ; r11
.hex F4F4F4F4 ; r12
.hex 00feffff ; r14
@@ -0,0 +1,490 @@
; Warrior X86 32 bits by goyo.
; Despues del RevientaViejas (r2con2018), viene: 'GORDASCO'
; bot para r2wars (r2con2020)
; Básicamente un replicator con problemas de peso
.bits 32
Main:
CALL Boot
Boot:
POP ESI
JMP replicator
# Esto para engordar el binario a 512 bytes y reducir el area de busqueda inicial del otro bot a 512.
# Si es rápido podría encontrar al otro antes de que se mueva si es que se mueve.
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
.byte 0xff
replicator:
CLD
MOV BX,0x3d7 ; memory top
MOV EDI,ESI
ADD SI,461 ; offset Payload - offset Main
MOV EAX,ESI
ADD EDI,40 ; only for 1st replication
MOV [EDX],EAX ; Por si alguien se esconde en 0x0 o en 0x3ff y le pillo..
MOV [EBX+36],EAX
Payload:
MOV ESI,EAX ; payload start
MOV CL,0x0A ; loop rep // attack // copy to the last .byte 0xcc
SUB EDI,40+40+3 ; separation ( 40 from last movsd + 40 from new movsd + 3 extra)
JNC Nocheck ; check limits
MOV EDI,EBX
Nocheck:
MOV EAX,EDI
REP MOVSD ; replicator
JMP EAX
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
.byte 0xcc
@@ -0,0 +1,19 @@
lea rsp, [0x25]
mov rbx, qword[rsp]
mov rcx, qword[rsp+8]
mov r10, 0x25f
mov r11, 0x3f0
mov r12, 0x10
add rsp, r10
and rsp, r11
add rsp, r12
push rcx
push rbx
jmp rsp
nop
nop
nop
nop
nop
nop
@@ -0,0 +1,8 @@
dec rax
mov rcx, 126
mov rsp, 0x400
mov rbx, 0xf3eb505050505050
mov rdx, 0x5050505050ab48f3
push rbx
push rdx
jmp rsp
@@ -0,0 +1,38 @@
; r2wars warrior by zutle
; >> So you want to play the pusha game? :D
;
; The logic below generates the following code:
;
;
;payload:
; test sp, sp
; jnz replicate
; mov sp, 0x400
;replicate:
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; pushal
; mov [esp + 0xc], ecx
; mov eax, esp
; jmp eax
call start
start:
pop esp
and esp, 0xffffff00
add esp, 0x20
mov edx, 0xe0ffe089
mov ebx, 0x0c244c89
mov ecx, 0x60606060
mov ebp, 0x60606060
mov esi, 0x0400bc66
mov edi, 0x0475e485
pushal
mov [esp + 0xc], ecx
mov eax, esp
jmp eax
@@ -0,0 +1,18 @@
; This bot sucks but I wamted to make something
mov esp, 0x3de
mov edx, 0xdead
mov ebx, 0xdead
mov ecx, 0xdead
jmp loop
hijack:
jmp eax
loop:
inc al
cmp eax, 0x3de
jle continue
xor eax, eax
continue:
cmp [eax], 0x00
jne hijack
pushal
jmp loop
@@ -0,0 +1,16 @@
mov esp, 0x3c8
mov ebx, 0x01606060
mov edx, 0x664949cc
mov ecx, 0x0080fc81
mov eax, 0xbc66f277
pushad
mov dword ptr[esp+0x20],0xeceb0390
call get_eip
get_eip:
pop esp
mov ecx, 0xFFFFFFe9
mov eax, 0x3b8
jmp eax
@@ -0,0 +1,19 @@
; her isimizde hayirlisi olsun
; pushad loopunu 0x14 civarına unpack ettikten sonra
; oraya ziplayip 0x400'den geriye pushad yapmaya baslar
; v3: a longer pushad init
pack:
mov edi, 0x00000280
mov esi, 0x6060fc89
mov ebp, 0x60606060
; esp
mov ebx, 0x60606060
mov edx, 0x60606060
mov ecx, 0x0400bc60
mov eax, 0xeaeb0000
unpack:
mov esp, 0x020
pushad
mov dword [esp + 4 + 8], 0x60606060
add esp, 0x4 ; if shorter, tune this
jmp esp
@@ -0,0 +1,50 @@
; "her isimizde hayirlisi olsun"
; a replicator bot. This one unpacks it's main loop payload
; around 0xc and jumps to there. In the loop, it first fills
; upper half of the arena then bottom half of the arena using
; pushad's.
;
; v1: initial; pushad from 0x400 through 0x0 result: 5 of 9
; v2: I don't remember not competed
; v3: a longer pushad sequence in init phase for quickscoping result: 5 of 13 && 8 of 14
; v4: the longest packed loop using all registers for just tryin'. result: 10 of 15
;
;
; pack contents are below
;;;;;;;;;;;;;;;;;;;;;;;;;;
; mov esp, edi
; loop:
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; pushad
; mov esp, 0x400
; jmp loop
pack:
mov edi, 0x00000280
mov esi, 0x6060fc89
mov ebp, 0x60606060
; esp popped here as 0x20 (a bad instruction). must be corrected in unpack loop
mov ebx, 0x60606060
mov edx, 0x60606060
mov ecx, 0x0400bc60
mov eax, 0xeaeb0000
unpack:
mov esp, 0x020
pushad
mov dword [esp + 4 + 8], 0x60606060 ; fix popped esp value
add esp, 0x4 ; tune this according to pack length
jmp esp
@@ -0,0 +1,19 @@
call init
init:
pop esp
add esp, 0x26
mov dword [eax], esp ; esp saved @0x0
sub esp, 0x20
save:
popad
jmp restore
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
.hex 0xcccccccc
restore:
mov esp, dword [0x0]
add esp, 0x20
xor esi, esi
mov dword [esi], esp
pushad
@@ -0,0 +1,18 @@
mov eax, 0xc3c3c3c3
mov ebx, 1024
mov edx, 0x84
mov ebp, eax
mov esi, 0xe4ff5160
mov edi, 0x606060e3
mov ecx, 0x420fd439
mov esp, 0xa8
call pwn
pwn:
pop esp
sub esp,4
pusha
mov esp, 0xa8
pusha
push ecx
jmp esp
@@ -0,0 +1,25 @@
# Anisse Astier
.arch arm
.bits 32
.hex 18d08fe2
.hex ff5fbde8
.hex 34d0b0e3
.hex ff07ade8
.hex f00fade8
.hex 0f005ee1
.hex 80d0a043
.hex 44f0a043
.hex 3fde0d42
.hex ff1fad48
.hex ff07ad48
.hex f00fad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ffffad48
.hex ecffff4a
.hex 0100005f
.hex ccc3ccc3
@@ -0,0 +1,15 @@
mov eax, 0xffffffff
mov ecx, eax
mov edx, eax
mov ebx, eax
mov ebp, eax
mov esi, eax
mov edi, 0xd
mov esp, 0x400
mov [edi], 0x20fc8360
mov [edi+4], 0xff600374
mov [edi+8], 0x0400bce7
mov [edi+12], 0xe7ff0000
;mov [edi], 0xe7ff6060
jmp edi
@@ -0,0 +1,18 @@
sub x20, x20, 16;
movk x21, 0x1ff;
bl start;
start:
movk x22, 0x8a;
strb w22, [x30, 23]; // patch ORR -> AND
ldp x0, x1, [x30, 16]; // copy
ldp x2, x3, [x30, 32]; // copy
add x20, x20, 32;
orr x20, x20, x21; // becomes AND
stp x0, x1, [x20, 120]; // stomp
stp x0, x1, [x20, 480]; // stomp
stp x2, x3, [x20, 496]; // stomp
stp x0, x1, [x20, 0]; // paste
stp x2, x3, [x20, 16]; // paste
br x20;
@@ -0,0 +1,165 @@
call init
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
init:
mov eax, 0x340
mov ebx, 0xc3c3c3c3
mov ecx, ebx ; trash
mov edx, 0x400 ; end of arena
mov edi, 0xd439c401
mov esi, 0x60e04f0f
mov ebp, 0xe4ff6060
call yolo_1
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
yolo_1:
mov esp, 0x210
pushad
mov esp, 0x66
pushad
mov esp, 0x3f9
pushad
call yolo_2
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
yolo_2:
mov esp, eax ; relocate to `eax`
pushad
pushad
mov eax, 0x99 ; first address after reloc
jmp esp
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
syscall
Loaded 100 of 210 files, more files were not shown because too many files have changed in this diff. Show more