diff --git a/Dockerfile b/Dockerfile index 0ff6728..ec7796f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,28 @@ +# Build stage FROM rust:latest AS builder WORKDIR /app + +# Install nightly Rust +RUN rustup install nightly + +# Copy source COPY . . -RUN cargo build --release --bin medal -RUN strip target/release/medal +# Build with nightly and strip binary +RUN cargo +nightly build --release --bin medal && \ + strip target/release/medal + +# Runtime stage (minimal size) FROM debian:12-slim AS runtime -COPY --from=builder /app/target/release/medal /bin/medal -ENTRYPOINT ["/bin/medal"] \ No newline at end of file + +# Install ca-certificates for HTTPS requests +RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* + +# Copy binary from builder +COPY --from=builder /app/target/release/medal /usr/local/bin/medal + +# Expose port +EXPOSE 3000 + +# Run the web server +ENTRYPOINT ["/usr/local/bin/medal", "serve", "--port", "3000"] diff --git a/bot/.gitattributes b/bot/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/bot/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/bot/.gitignore b/bot/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/bot/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/bot/Dockerfile b/bot/Dockerfile new file mode 100644 index 0000000..14ee12b --- /dev/null +++ b/bot/Dockerfile @@ -0,0 +1,43 @@ +# Stage 1: Build MoonsecDeobfuscator +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS moonsec-builder +WORKDIR /build +COPY . . +RUN dotnet publish -c Release -o /app + +# Stage 2: Clone & Build Medal (Rust) +FROM rust:alpine AS medal-builder +WORKDIR /build +RUN apk add --no-cache git build-base +RUN rustup install nightly +RUN git clone https://github.com/xConixyCEO/medal.git +WORKDIR /build/medal +RUN cargo +nightly build --release --bin medal + +# Stage 3: Runtime (with Lua!) +FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine +WORKDIR /app + +# Install dependencies and fix Lua library loading +RUN apk add --no-cache \ + curl \ + lua5.4 \ + lua5.4-dev \ + icu-libs && \ + # Create symlinks for NLua + ln -sf /usr/lib/liblua5.4.so /usr/lib/liblua54.so && \ + # Ensure library path includes /usr/lib + echo "/usr/lib" > /etc/ld-musl-x86_64.path + +# Enable globalization support +ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=0 + +# Copy bot files +COPY --from=moonsec-builder /app/* ./ + +# Copy Medal binary +COPY --from=medal-builder /build/medal/target/release/medal ./medal + +# Make executables runnable +RUN chmod +x ./MoonsecDeobfuscator ./medal + +CMD ["dotnet", "MoonsecDeobfuscator.dll"] diff --git a/bot/LICENSE b/bot/LICENSE new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/bot/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/bot/MoonsecDeobfuscator.csproj b/bot/MoonsecDeobfuscator.csproj new file mode 100644 index 0000000..0080d39 --- /dev/null +++ b/bot/MoonsecDeobfuscator.csproj @@ -0,0 +1,25 @@ + + + + Exe + net9.0 + enable + enable + + 0200;8600;8618;8625;8632;3021 + + + + + + + + + + + + + + + + diff --git a/bot/MoonsecDeobfuscator.sln b/bot/MoonsecDeobfuscator.sln new file mode 100644 index 0000000..3a18d33 --- /dev/null +++ b/bot/MoonsecDeobfuscator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36705.20 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoonsecDeobfuscator", "MoonsecDeobfuscator.csproj", "{9C5F7678-617D-4024-BB68-8C64DE6FF97F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9C5F7678-617D-4024-BB68-8C64DE6FF97F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C5F7678-617D-4024-BB68-8C64DE6FF97F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C5F7678-617D-4024-BB68-8C64DE6FF97F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C5F7678-617D-4024-BB68-8C64DE6FF97F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4ED42D1F-1B4B-4B22-91AB-890F2C631550} + EndGlobalSection +EndGlobal diff --git a/bot/README.md b/bot/README.md new file mode 100644 index 0000000..452658a --- /dev/null +++ b/bot/README.md @@ -0,0 +1,82 @@ +# Moonsec Deobfuscator +This project aims to deobfuscate Lua scripts obfuscated using **MoonSec V3**. The deobfuscation process produces a **Lua 5.1 bytecode file**, which you can then decompile with your favorite Lua decompiler. Optionally, the tool can also generate a **disassembly** of the bytecode. + +## Usage +### Installation & Building +To install and build run the following commands. +```bash +git clone https://github.com/tupsutumppu/MoonsecDeobfuscator.git +cd MoonsecDeobfuscator +dotnet build -c Release +``` +### Command-Line +```plaintext +Devirtualize and dump bytecode to file: + -dev -i -o + +Devirtualize and dump bytecode disassembly to file: + -dis -i -o +``` +## Examples +Here we have a Lua script. Let's see what it looks like after deobfuscation. +```Lua +local chars = { "H", "e", "l", "l", "o ", "W", "o", "r", "l", "d", "!" } +local result = "" +for i = 1, #chars do + result = result .. chars[i] +end +print(result) +``` +After deobfuscation +```Lua +local v0 = { + "H", + "e", + "l", + "l", + "o ", + "W", + "o", + "r", + "l", + "d", + "!" +}; +local v1 = ""; +for v2 = 1, #v0 do + v1 = v1 .. v0[v2]; +end; +print(v1); +``` +Disassembly +```Lua +function func_f99e02d1(...) + [Slots: 12, Upvalues: 0, Constants: 12] + [ 0] NewTable | 0 | 11 | 0 | R0 = {} + [ 1] LoadK | 1 | 0 | 0 | R1 = "H" + [ 2] LoadK | 2 | 1 | 0 | R2 = "e" + [ 3] LoadK | 3 | 2 | 0 | R3 = "l" + [ 4] LoadK | 4 | 2 | 0 | R4 = "l" + [ 5] LoadK | 5 | 3 | 0 | R5 = "o " + [ 6] LoadK | 6 | 4 | 0 | R6 = "W" + [ 7] LoadK | 7 | 5 | 0 | R7 = "o" + [ 8] LoadK | 8 | 6 | 0 | R8 = "r" + [ 9] LoadK | 9 | 2 | 0 | R9 = "l" + [ 10] LoadK | 10 | 7 | 0 | R10 = "d" + [ 11] LoadK | 11 | 8 | 0 | R11 = "!" + [ 12] SetList | 0 | 11 | 1 | + [ 13] LoadK | 1 | 9 | 0 | R1 = "" + [ 14] LoadK | 2 | 10 | 0 | R2 = 1 + [ 15] Len | 3 | 0 | 0 | R3 = #R0 + [ 16] LoadK | 4 | 10 | 0 | R4 = 1 + [ 17] ForPrep | 2 | 3 | 0 | R2 -= R4; PC += 3 + [ 18] Move | 6 | 1 | 0 | R6 = R1 + [ 19] GetTable | 7 | 0 | 5 | R7 = R0[R5] + [ 20] Concat | 1 | 6 | 7 | R1 = R6 .. R7 + [ 21] ForLoop | 2 | -4 | 0 | R2 += R4; if loop continues then PC += -4; R5 = R2; + [ 22] GetGlobal | 2 | 11 | 0 | R2 = print + [ 23] Move | 3 | 1 | 0 | R3 = R1 + [ 24] Call | 2 | 2 | 1 | R2(R3) + [ 25] Return | 0 | 1 | 0 | return +end +``` diff --git a/bot/render.yaml b/bot/render.yaml new file mode 100644 index 0000000..6fc8b85 --- /dev/null +++ b/bot/render.yaml @@ -0,0 +1,15 @@ +services: + - type: web + name: moonsec-deobfuscator-bot + env: docker + dockerfilePath: ./Dockerfile + plan: free + branch: main + autoDeploy: true + dockerBuildTimeoutSeconds: 1800 + healthCheckPath: / + envVars: + - key: DISCORD_TOKEN + sync: false + - key: DOTNET_SYSTEM_GLOBALIZATION_INVARIANT + value: "1" diff --git a/bot/src/Deobfuscation/Bytecode/Deserializer.cs b/bot/src/Deobfuscation/Bytecode/Deserializer.cs new file mode 100644 index 0000000..d9983d9 --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Deserializer.cs @@ -0,0 +1,142 @@ +using MoonsecDeobfuscator.Bytecode.Models; +using MoonsecDeobfuscator.Deobfuscation.Utils; + +namespace MoonsecDeobfuscator.Deobfuscation.Bytecode; + +public enum ProtoStep +{ + Instructions, + Constants, + Functions, + NumParams, + + StringConstant, + NumberConstant, + BooleanConstant +} + +public class Deserializer(byte[] bytes, Context ctx) : BinaryReader(new MemoryStream(bytes)) +{ + private List ReadInstructions(Function function) + { + var size = ReadInt32(); + var instructions = new List(size); + + for (var i = 0; i < size; i++) + { + var descriptor = ReadByte(); + + if (GetBits(descriptor, 1, 1) != 0) + continue; + + var type = GetBits(descriptor, 2, 3); + var mask = GetBits(descriptor, 4, 6); + var instruction = new Instruction + { + OpNum = ReadInt16(), + A = ReadInt16(), + PC = i, + Function = function + }; + + switch (type) + { + case 0: + instruction.B = ReadInt16(); + instruction.C = ReadInt16(); + break; + case 1: + instruction.B = ReadInt32(); + break; + case 2: + instruction.B = ReadInt32() - (1 << 16); + break; + case 3: + instruction.B = ReadInt32() - (1 << 16); + instruction.C = ReadInt16(); + break; + } + + instruction.IsKA = GetBits(mask, 1, 1) == 1; + instruction.IsKB = GetBits(mask, 2, 2) == 1; + instruction.IsKC = GetBits(mask, 3, 3) == 1; + + instructions.Add(instruction); + } + + return instructions; + } + + private List ReadPrototypes() + { + var size = ReadInt32(); + var prototypes = new List(size); + + for (var i = 0; i < size; i++) + prototypes.Add(ReadFunction()); + + return prototypes; + } + + private List ReadConstants() + { + var size = ReadInt32(); + var constants = new List(size); + + for (var i = 0; i < size; i++) + { + var typeFlag = ReadByte(); + + if (!ctx.ConstantFormat.TryGetValue(typeFlag, out var type)) + { + constants.Add(new NilConstant()); + continue; + } + + switch (type) + { + case ProtoStep.BooleanConstant: + constants.Add(new BooleanConstant(ReadBoolean())); + break; + case ProtoStep.NumberConstant: + constants.Add(new NumberConstant(ReadDouble())); + break; + case ProtoStep.StringConstant: + var str = StringDecoding.DecodeConstant(ctx.ConstantKey, ReadBytes(ReadInt32())); + constants.Add(new StringConstant(str)); + break; + } + } + + return constants; + } + + public Function ReadFunction() + { + var function = new Function(); + + foreach (var step in ctx.ProtoFormat) + { + switch (step) + { + case ProtoStep.Constants: + function.Constants = ReadConstants(); + break; + case ProtoStep.Instructions: + function.Instructions = ReadInstructions(function); + break; + case ProtoStep.NumParams: + function.NumParams = ReadByte(); + break; + case ProtoStep.Functions: + function.Functions = ReadPrototypes(); + break; + } + } + + return function; + } + + private static int GetBits(int source, int start, int end) => + (source >> (start - 1)) & ((1 << (end - start + 1)) - 1); +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Disassembler.cs b/bot/src/Deobfuscation/Bytecode/Disassembler.cs new file mode 100644 index 0000000..f75338b --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Disassembler.cs @@ -0,0 +1,212 @@ +using System.Text; +using MoonsecDeobfuscator.Bytecode.Models; + +namespace MoonsecDeobfuscator.Deobfuscation.Bytecode; + +public class Disassembler(Function rootFunction) +{ + private readonly StringBuilder _builder = new(); + + public string Disassemble() + { + _builder.AppendLine("-- wsg hello join galactic services rn!"); + DisassembleFunction(rootFunction); + return _builder.ToString(); + } + + private void DisassembleFunction(Function function) + { + _builder.Append($"function {function.Name}("); + + for (var i = 0; i < function.NumParams; i++) + { + _builder.Append($"R{i}"); + + if (i + 1 < function.NumParams) + _builder.Append(", "); + } + + if (function.IsVarArgFlag == 2) + _builder.Append(function.NumParams > 0 ? ", ..." : "..."); + + _builder.AppendLine(")"); + _builder.AppendLine( + $"\t[Slots: {function.MaxStackSize}, Upvalues: {function.NumUpvalues}, Constants: {function.Constants.Count}]"); + + var instructions = function.Instructions; + + for (var i = 0; i < instructions.Count; i++) + { + _builder.Append($"\t[{i,4}]\t"); + DisassembleInstruction(instructions[i]); + } + + _builder.AppendLine("end"); + + foreach (var childFunction in function.Functions) + DisassembleFunction(childFunction); + } + + private void DisassembleInstruction(Instruction instruction) + { + var A = instruction.A; + var B = instruction.B; + var C = instruction.C; + + if (instruction.OpCode != OpCode.Unknown) + _builder.Append($"{instruction.OpCode,12}\t| {A,4} | {B,4} | {C,4} |"); + else if (instruction.IsDead) + _builder.Append($"{"DEAD",12}\t| {"-",4} | {"-",4} | {"-",4} |"); + else + _builder.Append($"{instruction.OpNum,12}\t| {A,4} | {B,4} | {C,4} |"); + + if (instruction.OpCode != OpCode.Unknown) + { + _builder.Append('\t'); + _builder.Append(GenAnnotation(instruction)); + } + + _builder.AppendLine(); + } + + private static string GenAnnotation(Instruction instruction) + { + var A = instruction.A; + var B = instruction.B; + var C = instruction.C; + var function = instruction.Function; + + switch (instruction.OpCode) + { + case OpCode.GetGlobal: + return $"R{A} = {((StringConstant) function.Constants[B]).Value}"; + case OpCode.SetGlobal: + return $"{((StringConstant) function.Constants[B]).Value} = R{A}"; + case OpCode.LoadK: + return $"R{A} = {function.Constants.ElementAtOrDefault(B)}"; + case OpCode.LoadNil: + return B - A == 0 ? $"R{A} = nil" : $"R{A}->R{B} = nil"; + case OpCode.LoadBool: + var value = B != 0 ? "true" : "false"; + var skip = C != 0 ? "; PC += 1" : ""; + return $"R{A} = {value}{skip}"; + case OpCode.Move: + return $"R{A} = R{B}"; + case OpCode.Jmp: + return $"PC += {B}"; + case OpCode.GetUpval: + return $"R{A} = UPVALUE_{B}"; + case OpCode.SetUpval: + return $"UPVALUE_{B} = R{A}"; + case OpCode.GetTable: + return $"R{A} = R{B}[{RegisterOrConstant(C, function)}]"; + case OpCode.SetTable: + return $"R{A}[{RegisterOrConstant(B, function)}] = {RegisterOrConstant(C, function)}"; + case OpCode.NewTable: + return $"R{A} = {{}}"; + case OpCode.Self: + return $"R{A + 1} = R{B}; R{A} = R{B}[{RegisterOrConstant(C, function)}]"; + case OpCode.Add: + return $"R{A} = {RegisterOrConstant(B, function)} + {RegisterOrConstant(C, function)}"; + case OpCode.Sub: + return $"R{A} = {RegisterOrConstant(B, function)} - {RegisterOrConstant(C, function)}"; + case OpCode.Mul: + return $"R{A} = {RegisterOrConstant(B, function)} * {RegisterOrConstant(C, function)}"; + case OpCode.Div: + return $"R{A} = {RegisterOrConstant(B, function)} / {RegisterOrConstant(C, function)}"; + case OpCode.Mod: + return $"R{A} = {RegisterOrConstant(B, function)} % {RegisterOrConstant(C, function)}"; + case OpCode.Pow: + return $"R{A} = {RegisterOrConstant(B, function)} ^ {RegisterOrConstant(C, function)}"; + case OpCode.Unm: + return $"R{A} = -R{B}"; + case OpCode.Not: + return $"R{A} = not R{B}"; + case OpCode.Len: + return $"R{A} = #R{B}"; + case OpCode.Concat: + var result = new StringBuilder(); + result.Append($"R{A} = "); + + for (var i = B; i <= C; i++) + { + result.Append($"R{i}"); + + if (i + 1 <= C) + result.Append(" .. "); + } + + return result.ToString(); + case OpCode.Eq: + case OpCode.Lt: + case OpCode.Le: + var op = instruction.OpCode switch + { + OpCode.Eq => A == 0 ? "==" : "~=", + OpCode.Lt => A == 0 ? "<" : ">", + OpCode.Le => A == 0 ? "<=" : ">=", + _ => " ?? " + }; + return $"if {RegisterOrConstant(B, function)} {op} {RegisterOrConstant(C, function)} then PC += 1"; + case OpCode.Test: + return $"if {(C == 0 ? $"not R{A}" : $"R{A}")} then PC += 1"; + case OpCode.TestSet: + return $"if {(C == 0 ? $"not R{B}" : $"R{B}")} then R{A} = R{B} else PC += 1"; + case OpCode.Call: + var lhs = C switch + { + 0 => $"R{A}->top = ", + 1 => "", + _ => string.Join(", ", Enumerable.Range(0, C - 1).Select(i => $"R{A + i}")) + " = " + }; + var args = B switch + { + 0 => $"R{A + 1}->top", + 1 => "", + _ => string.Join(", ", Enumerable.Range(1, B - 1).Select(i => $"R{A + i}")) + }; + + var r = $"{lhs}R{A}({args})"; + return r; + case OpCode.TailCall: + return B switch + { + > 1 => $"return R{A}({string.Join(", ", Enumerable.Range(1, B - 1).Select(i => $"R{A + i}"))})", + 0 => $"return R{A}()", + 1 => $"return R{A}(R{A + 1})", + _ => $"return R{A}()" + }; + case OpCode.Return: + return B switch + { + 0 => $"return R{A}->top", + 1 => "return", + _ => $"return {string.Join(", ", Enumerable.Range(0, B - 1).Select(i => $"R{A + i}"))}" + }; + case OpCode.ForLoop: + return $"R{A} += R{A + 2}; if loop continues then PC += {B}; R{A + 3} = R{A};"; + case OpCode.ForPrep: + return $"R{A} -= R{A + 2}; PC += {B}"; + case OpCode.TForLoop: + var targets = string.Join(", ", Enumerable.Range(3, C).Select(i => $"R{A + i}")); + var call = $"R{A}(R{A + 1}, R{A + 2})"; + var body = $"if R{A + 3} ~= nil then R{A + 2} = R{A + 3} else PC += 1 end"; + return $"{targets} = {call}; {body}"; + case OpCode.Closure: + return $"R{A} = {function.Functions[B].Name}"; + case OpCode.VarArg: + var a = B switch + { + 0 => $"R{A}->top", + 1 => "", + _ => string.Join(", ", Enumerable.Range(0, B - 1).Select(i => $"R{A + i}")) + }; + return $"{a} = ..."; + } + + return ""; + } + + private static string RegisterOrConstant(int register, Function function) => + register > 255 ? function.Constants[register - 256].ToString()! : $"R{register}"; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Models/Constant.cs b/bot/src/Deobfuscation/Bytecode/Models/Constant.cs new file mode 100644 index 0000000..e7b9428 --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Models/Constant.cs @@ -0,0 +1,29 @@ +namespace MoonsecDeobfuscator.Bytecode.Models; + +public abstract class Constant; + +public class StringConstant(string value) : Constant +{ + public readonly string Value = value; + + public override string ToString() => $"\"{Value}\""; +} + +public class NumberConstant(double value) : Constant +{ + public readonly double Value = value; + + public override string ToString() => Value.ToString(); +} + +public class BooleanConstant(bool value) : Constant +{ + public readonly bool Value = value; + + public override string ToString() => Value.ToString().ToLower(); +} + +public class NilConstant : Constant +{ + public override string ToString() => "nil"; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Models/Function.cs b/bot/src/Deobfuscation/Bytecode/Models/Function.cs new file mode 100644 index 0000000..bbc4b3c --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Models/Function.cs @@ -0,0 +1,11 @@ +namespace MoonsecDeobfuscator.Bytecode.Models; + +public class Function +{ + public List Instructions = null!; + public List Constants = null!; + public List Functions = null!; + + public byte MaxStackSize, NumParams, NumUpvalues, IsVarArgFlag; + public readonly string Name = $"func_{Guid.NewGuid().ToString("N")[..8]}"; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Models/Instruction.cs b/bot/src/Deobfuscation/Bytecode/Models/Instruction.cs new file mode 100644 index 0000000..283e1ad --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Models/Instruction.cs @@ -0,0 +1,75 @@ +namespace MoonsecDeobfuscator.Bytecode.Models; + +public class Instruction +{ + public int A, B, C, OpNum, PC; + public bool IsKA, IsKB, IsKC, IsDead; + + public Function Function = null!; + public OpCode OpCode = OpCode.Unknown; + + public override string ToString() + { + if (OpCode != OpCode.Unknown) + return $"{OpCode,12}\t| {A,4} | {B,4} | {C,4} |"; + + if (IsDead) + return $"{"DEAD",12}\t| {"-",4} | {"-",4} | {"-",4} |"; + + return $"{OpNum,12}\t| {A,4} | {B,4} | {C,4} |"; + } + + public OpType GetOpType() + { + switch (OpCode) + { + case OpCode.Move: + case OpCode.LoadNil: + case OpCode.GetUpval: + case OpCode.SetUpval: + case OpCode.Unm: + case OpCode.Not: + case OpCode.Len: + case OpCode.Return: + case OpCode.VarArg: + return OpType.AB; + case OpCode.LoadK: + case OpCode.GetGlobal: + case OpCode.SetGlobal: + case OpCode.Closure: + return OpType.ABx; + case OpCode.LoadBool: + case OpCode.GetTable: + case OpCode.SetTable: + case OpCode.Add: + case OpCode.Sub: + case OpCode.Mul: + case OpCode.Div: + case OpCode.Mod: + case OpCode.Pow: + case OpCode.Concat: + case OpCode.Call: + case OpCode.TailCall: + case OpCode.Self: + case OpCode.Eq: + case OpCode.Lt: + case OpCode.Le: + case OpCode.TestSet: + case OpCode.NewTable: + case OpCode.SetList: + return OpType.ABC; + case OpCode.Jmp: + return OpType.sBx; + case OpCode.Test: + case OpCode.TForLoop: + return OpType.AC; + case OpCode.ForPrep: + case OpCode.ForLoop: + return OpType.AsBx; + case OpCode.Close: + return OpType.A; + } + + throw new Exception("Invalid opcode in GetOpType"); + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Models/OpCode.cs b/bot/src/Deobfuscation/Bytecode/Models/OpCode.cs new file mode 100644 index 0000000..eb4aa98 --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Models/OpCode.cs @@ -0,0 +1,132 @@ +namespace MoonsecDeobfuscator.Bytecode.Models; + +public enum OpCode +{ + // MOVE A B R(A) := R(B) + Move, + + // LOADK A Bx R(A) := Kst(Bx) + LoadK, + + // LOADBOOL A B C R(A) := (Bool)B; if (C) PC++ + LoadBool, + + // LOADNIL A B R(A) := ... := R(B) := nil + LoadNil, + + // GETUPVAL A B R(A) := UpValue[B] + GetUpval, + + // GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)] + GetGlobal, + + // GETTABLE A B C R(A) := R(B)[RK(C)] + GetTable, + + // SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A) + SetGlobal, + + // SETUPVAL A B UpValue[B] := R(A) + SetUpval, + + // SETTABLE A B C R(A)[RK(B)] := RK(C) + SetTable, + + // NEWTABLE A B C R(A) := {} (size = B,C) + NewTable, + + // SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] + Self, + + // ADD A B C R(A) := RK(B) + RK(C) + Add, + + // SUB A B C R(A) := RK(B) – RK(C) + Sub, + + // MUL A B C R(A) := RK(B) * RK(C) + Mul, + + // DIV A B C R(A) := RK(B) / RK(C) + Div, + + // MOD A B C R(A) := RK(B) % RK(C) + Mod, + + // POW A B C R(A) := RK(B) ^ RK(C) + Pow, + + // UNM A B R(A) := -R(B) + Unm, + + // NOT A B R(A) := not R(B) + Not, + + // LEN A B R(A) := length of R(B) + Len, + + // CONCAT A B C R(A) := R(B).. ... ..R(C) + Concat, + + // JMP sBx PC += sBx + Jmp, + + // EQ A B C if ((RK(B) == RK(C)) ~= A) then PC++ + Eq, + + // LT A B C if ((RK(B) < RK(C)) ~= A) then PC++ + Lt, + + // LE A B C if ((RK(B) <= RK(C)) ~= A) then PC++ + Le, + + // TEST A C if not (R(A) <=> C) then PC++ + Test, + + // TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else PC++ + TestSet, + + // CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) + Call, + + // TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1)) + TailCall, + + // RETURN A B return R(A), ... ,R(A+B-2) + Return, + + /* + FORLOOP A sBx R(A) += R(A+2) + if R(A) =) R(A) + Close, + + // CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) + Closure, + + // VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg + VarArg, + + Unknown +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Models/OpType.cs b/bot/src/Deobfuscation/Bytecode/Models/OpType.cs new file mode 100644 index 0000000..e6a595f --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Models/OpType.cs @@ -0,0 +1,13 @@ +namespace MoonsecDeobfuscator.Bytecode.Models; + +public enum OpType +{ + AB, + ABx, + ABC, + sBx, + AC, + AsBx, + A, + None +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Bytecode/Serializer.cs b/bot/src/Deobfuscation/Bytecode/Serializer.cs new file mode 100644 index 0000000..da194f6 --- /dev/null +++ b/bot/src/Deobfuscation/Bytecode/Serializer.cs @@ -0,0 +1,139 @@ +using System.Text; +using MoonsecDeobfuscator.Bytecode.Models; + +namespace MoonsecDeobfuscator.Deobfuscation.Bytecode; + +public class Serializer(Stream stream) : BinaryWriter(stream) +{ + private void WriteString(string data) + { + var bytes = Encoding.UTF8.GetBytes(data); + + Write((ulong) (bytes.Length + 1)); + Write(bytes); + Write((byte) 0); + } + + private void WriteFunction(Function function) + { + WriteString(""); + Write(0); + Write(0); + + Write(function.NumUpvalues); + Write(function.NumParams); + Write(function.IsVarArgFlag); + Write(function.MaxStackSize); + + WriteInstructions(function.Instructions); + WriteConstants(function.Constants); + WriteFunctions(function.Functions); + + Write(0); + Write(0); + Write(0); + } + + private void WriteFunctions(List functions) + { + Write(functions.Count); + + foreach (var function in functions) + WriteFunction(function); + } + + private void WriteConstants(List constants) + { + Write(constants.Count); + + foreach (var constant in constants) + { + switch (constant) + { + case StringConstant sc: + Write((byte) 4); + WriteString(sc.Value); + break; + case NumberConstant nc: + Write((byte) 3); + Write(nc.Value); + break; + case BooleanConstant bc: + Write((byte) 1); + Write((byte) (bc.Value ? 1 : 0)); + break; + default: + Write((byte) 0); + break; + } + } + } + + private void WriteInstructions(List instructions) + { + Write(instructions.Count); + + foreach (var instruction in instructions) + { + var data = 0u; + data |= (uint) instruction.OpCode; + + switch (instruction.GetOpType()) + { + case OpType.A: + data |= Mask(instruction.A, 8) << 6; + break; + case OpType.AB: + data |= Mask(instruction.A, 8) << 6; + data |= Mask(instruction.B, 9) << 23; + break; + case OpType.AC: + data |= Mask(instruction.A, 8) << 6; + data |= Mask(instruction.C, 9) << 14; + break; + case OpType.ABC: + data |= Mask(instruction.A, 8) << 6; + data |= Mask(instruction.B, 9) << 23; + data |= Mask(instruction.C, 9) << 14; + break; + case OpType.ABx: + data |= Mask(instruction.A, 8) << 6; + data |= Mask(instruction.B, 18) << 14; + break; + case OpType.AsBx: + data |= Mask(instruction.A, 8) << 6; + data |= Mask(instruction.B + 131_071, 18) << 14; + break; + case OpType.sBx: + data |= Mask(instruction.B + 131_071, 18) << 14; + break; + } + + Write(data); + } + } + + private void WriteHeader() + { + Write( + [ + 0x1B, 0x4C, 0x75, 0x61, + 0x51, + 0, + 1, + 4, + 8, + 4, + 8, + 0 + ]); + } + + public void Serialize(Function function) + { + WriteHeader(); + WriteFunction(function); + } + + private static uint Mask(int value, int bits) => (uint) value & ((1u << bits) - 1); +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/BytecodeDeobfuscator.cs b/bot/src/Deobfuscation/BytecodeDeobfuscator.cs new file mode 100644 index 0000000..360e29a --- /dev/null +++ b/bot/src/Deobfuscation/BytecodeDeobfuscator.cs @@ -0,0 +1,359 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Bytecode.Models; +using MoonsecDeobfuscator.Deobfuscation.Rewriters; +using MoonsecDeobfuscator.Deobfuscation.Utils; +using MoonsecDeobfuscator.Deobfuscation.Walkers; +using Function = MoonsecDeobfuscator.Bytecode.Models.Function; + +namespace MoonsecDeobfuscator.Deobfuscation; + +public class Handler(Block body, string fingerprint) +{ + public readonly Block Body = body; + public readonly string Fingerprint = fingerprint; +} + +public class BytecodeDeobfuscator(Function function, Context ctx) +{ + private readonly Dictionary> _handlerMapping = []; + private readonly Function _rootFunction = function; + + public Function Deobfuscate() + { + CreateHandlerMapping(); + DeobfuscateOpcodes(_rootFunction); + DeobfuscateControlFlow(_rootFunction); + FixProgramEntry(); + RebuildConstantPool(_rootFunction); + SetFlags(_rootFunction); + _rootFunction.IsVarArgFlag = 2; + return _rootFunction; + } + + private static void DeobfuscateControlFlow(Function function) + { + var jumpReferences = ComputeJumpReferences(function); + + RemoveDeadCode(function); + RemoveTestFlip(function); + FixTailCall(function); + FixJumpOffsets(function, jumpReferences); + + foreach (var childFunction in function.Functions) + DeobfuscateControlFlow(childFunction); + } + + private static void RebuildConstantPool(Function function) + { + var remapping = new Dictionary(function.Constants.Count); + var newOrder = new List(function.Constants.Count); + var next = 0; + + foreach (var instruction in function.Instructions) + { + switch (instruction.OpCode) + { + case OpCode.LoadK: + case OpCode.GetGlobal: + case OpCode.SetGlobal: + instruction.B = Remap(instruction.B); + break; + case OpCode.SetTable: + case OpCode.Eq: + case OpCode.Lt: + case OpCode.Le: + case OpCode.Add: + case OpCode.Sub: + case OpCode.Mul: + case OpCode.Div: + case OpCode.Mod: + case OpCode.Pow: + instruction.B = RemapRK(instruction.B); + instruction.C = RemapRK(instruction.C); + break; + case OpCode.GetTable: + case OpCode.Self: + instruction.C = RemapRK(instruction.C); + break; + } + } + + function.Constants = newOrder; + function.Functions.ForEach(RebuildConstantPool); + return; + + int Remap(int oldIdx) + { + if (!remapping.TryGetValue(oldIdx, out var newIdx)) + { + newIdx = next++; + remapping[oldIdx] = newIdx; + newOrder.Add(function.Constants[oldIdx]); + } + + return newIdx; + } + + int RemapRK(int operand) => operand >= 256 ? Remap(operand - 256) + 256 : operand; + } + + private static void RemoveTestFlip(Function function) + { + var instructions = function.Instructions; + + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + + if (instruction.OpCode is not (OpCode.Eq or OpCode.Lt or OpCode.Le or OpCode.Test)) + continue; + + var next1 = instructions[i + 1]; + var next2 = instructions[i + 2]; + + if (!(next1.OpCode == OpCode.Jmp && next2.OpCode == OpCode.Jmp)) + continue; + + switch (instruction.OpCode) + { + case OpCode.Eq: + case OpCode.Lt: + case OpCode.Le: + instruction.A = instruction.A == 1 ? 0 : 1; + break; + case OpCode.Test: + instruction.C = instruction.C == 1 ? 0 : 1; + break; + } + + instructions.RemoveAt(i + 1); + } + } + + /* + Insert Return after TailCall if not present + */ + private static void FixTailCall(Function function) + { + var instructions = function.Instructions; + + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + + if (instruction.OpCode != OpCode.TailCall) + continue; + + if (i + 1 < instructions.Count && instructions[i + 1].OpCode == OpCode.Return) + continue; + + instructions.Insert(i + 1, new Instruction + { + OpCode = OpCode.Return, + A = instruction.A + }); + } + } + + /* + The actual program starts after this check and anything before is to be removed. + + if GLOBAL ~= "This file was protected with MoonSec V3" then + return + end + */ + private void FixProgramEntry() + { + var check = _rootFunction.Instructions + .FirstOrDefault(instr => instr is { OpCode: OpCode.Eq, C: > 255 } + && instr.Function.Constants[instr.C - 256] is StringConstant sc + && sc.Value.StartsWith("This file was protected with MoonSec V3")); + + if (check == null) + return; + + var idx = _rootFunction.Instructions.IndexOf(check); + + for (var i = idx; i < _rootFunction.Instructions.Count; i++) + { + var instruction = _rootFunction.Instructions[i]; + + if (instruction.OpCode == OpCode.Return) + { + _rootFunction.Instructions.RemoveRange(0, i + 1); + break; + } + } + + RemoveUnusedFunctions(); + } + + /* + FixProgramEntry might leave some unused functions so we remove them here + */ + private void RemoveUnusedFunctions() + { + var functionReferences = new Dictionary(); + + foreach (var instruction in _rootFunction.Instructions) + { + if (instruction.OpCode == OpCode.Closure) + functionReferences[instruction] = _rootFunction.Functions[instruction.B]; + } + + _rootFunction.Functions.RemoveAll(f => !functionReferences.ContainsValue(f)); + + foreach (var (instr, function) in functionReferences) + instr.B = _rootFunction.Functions.IndexOf(function); + } + + private static void RemoveDeadCode(Function function) + { + function.Instructions.RemoveAll(instruction => instruction.IsDead); + } + + private static void FixJumpOffsets(Function function, Dictionary jumpReferences) + { + var instructions = function.Instructions; + var pos = new Dictionary(); + + for (var i = 0; i < instructions.Count; i++) + pos[instructions[i]] = i; + + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + + if (jumpReferences.TryGetValue(instruction, out var target)) + instruction.B = pos[target] - (i + 1); + } + } + + private static void SetFlags(Function function) + { + function.IsVarArgFlag = 0; + + var maxA = 0; + + foreach (var instruction in function.Instructions) + { + var opcode = instruction.OpCode; + var A = instruction.A; + + if (A > maxA) + maxA = A; + + if (opcode == OpCode.Closure) + function.Functions[instruction.B].NumUpvalues = (byte) instruction.C; + else if (opcode == OpCode.VarArg) + function.IsVarArgFlag = 2; + } + + function.MaxStackSize = (byte) (maxA + 1); + function.Functions.ForEach(SetFlags); + } + + private static Dictionary ComputeJumpReferences(Function function) + { + var jumpReferences = new Dictionary(); + var instructions = function.Instructions; + + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + + if (instruction.OpCode is OpCode.Jmp or OpCode.ForLoop or OpCode.ForPrep) + jumpReferences[instruction] = instructions[(i + instruction.B) + 1]; + } + + return jumpReferences; + } + + private void DeobfuscateOpcodes(Function function) + { + var instructions = function.Instructions; + var jmpSet = new HashSet(); + + for (var i = 0; i < instructions.Count; i++) + { + var instruction = instructions[i]; + var handlers = _handlerMapping[instruction.OpNum]; + + foreach (var handler in handlers) + { + DeobfuscateOpcode(instruction, handler); + + if (instruction.OpCode == OpCode.Jmp) + jmpSet.Add(i + instruction.B + 1); + + if (instruction.OpCode is OpCode.Return or OpCode.TailCall) + { + SkipDeadCode(instructions, jmpSet, ref i); + break; + } + + if (handler != handlers.Last() && i + 1 < instructions.Count) + instruction = instructions[++i]; + } + } + + function.Functions.ForEach(DeobfuscateOpcodes); + } + + private static void SkipDeadCode(List instructions, HashSet jmpSet, ref int i) + { + while (++i < instructions.Count) + { + var nextIndex = i; + + if (jmpSet.Contains(nextIndex)) + { + i--; + break; + } + + instructions[i].IsDead = true; + } + } + + private static void DeobfuscateOpcode(Instruction instruction, Handler handler) + { + if (OpCodes.StaticOpcodes.TryGetValue(handler.Fingerprint, out var it)) + { + instruction.OpCode = it.Item1; + it.Item2?.Invoke(instruction); + } + else + { + Console.Error.WriteLine($"Could not identify handler: {handler.Fingerprint}"); + Console.Error.WriteLine(PrettyPrinter.AsString(handler.Body)); + } + } + + private void CreateHandlerMapping() + { + var solvedVmTree = new TreeSolver(ctx.VmTree, "enum").Solve(); + + foreach (var entry in solvedVmTree) + CreateHandler(entry.Key, entry.Value); + } + + private void CreateHandler(int opcode, Block body) + { + var handlers = body.Statements + .WindowedByDiscardedPairs((a, b) => Matching.IsPcIncrement(a) && Matching.IsInstAssign(b)) + .Select(stats => + { + var block = new Block + { + Statements = [..stats] + }.Clone(); + new HandlerRewriter().Rewrite(block, Order.PostOrder, symbols: true, fixedPoint: true); + return block; + }) + .Select(block => new Handler(block, FingerprintGenerator.Generate(block))) + .ToList(); + + _handlerMapping[opcode] = handlers; + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Context.cs b/bot/src/Deobfuscation/Context.cs new file mode 100644 index 0000000..0bd8eb3 --- /dev/null +++ b/bot/src/Deobfuscation/Context.cs @@ -0,0 +1,20 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Deobfuscation.Bytecode; + +namespace MoonsecDeobfuscator.Deobfuscation; + +public class Context +{ + public readonly Dictionary IdentifiedNames = []; + public readonly List KeyExpressions = []; + + public readonly List ProtoFormat = []; + public readonly Dictionary ConstantFormat = []; + + public LocalFunction Wrapper; + public If VmTree; + public string BytecodeString; + + public int BytecodeKey, ConstantKey; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Deobfuscator.cs b/bot/src/Deobfuscation/Deobfuscator.cs new file mode 100644 index 0000000..27d90e2 --- /dev/null +++ b/bot/src/Deobfuscation/Deobfuscator.cs @@ -0,0 +1,103 @@ +using System.Text; +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Bytecode.Models; +using MoonsecDeobfuscator.Deobfuscation.Bytecode; +using MoonsecDeobfuscator.Deobfuscation.Rewriters; +using MoonsecDeobfuscator.Deobfuscation.Utils; +using MoonsecDeobfuscator.Deobfuscation.Walkers; +using NLua; +using Function = MoonsecDeobfuscator.Bytecode.Models.Function; + +namespace MoonsecDeobfuscator.Deobfuscation; + +public class Deobfuscator +{ + private Context _ctx = new(); + private Block _root = null!; + + public Function Deobfuscate(string code, bool antiTamper = false) + { + _root = Block.FromString(code); + + new Renamer().Walk(_root); + new ConstantReplacer(DecodeConstants()).Rewrite(_root, Order.PreOrder); + new ConstantFolder().Rewrite(_root, Order.PostOrder); + new Analyzer(_ctx).Walk(_root, symbols: true); + + if (_root.Statements.Count > 3 && !antiTamper) + return Deobfuscate(HandleAntiTamper(), true); + + new ControlFlowSolver().Rewrite(_ctx.Wrapper, Order.PostOrder); + new Renamer(_ctx.IdentifiedNames).Walk(_root); + + var function = DeserializeBytecode(); + var bytecodeDeobfuscator = new BytecodeDeobfuscator(function, _ctx); + + function = bytecodeDeobfuscator.Deobfuscate(); + + return function; + } + + private Dictionary DecodeConstants() + { + var constants = StringCollector.Collect(_root); + + return constants + .Select(it => it.Item1 != null + ? StringDecoding.Decode(it.Item2, (int) it.Item1) + : StringDecoding.DecodeEscape(it.Item2)) + .Select(StringDecoding.DecodeConstants) + .SelectMany(map => map) + .ToDictionary(entry => entry.Key, entry => entry.Value); + } + + private string HandleAntiTamper() + { + var function = DeserializeBytecode(); + var instructions = function.Instructions + .Where(instr => instr is { IsKA: false, IsKB: true, IsKC: false }) + .ToList(); + + // why tf is this static + var constant = function.Constants[instructions[^2].B - 1]; + var key = ((NumberConstant) constant).Value; + + var bytecodeString = ((StringLiteral) ((Assign) _root.Statements[2]).Values[0]).Value[1..^1]; + var scriptString = ((StringLiteral) ((Assign) _root.Statements[3]).Values[0]).Value[1..^1]; + + _ctx = new Context + { + BytecodeString = bytecodeString + }; + + return Encoding.UTF8.GetString(StringDecoding.Decode(scriptString, (int) key)); + } + + private Function DeserializeBytecode() + { + SolveKeys(); + + var bytecode = StringDecoding.Decode(_ctx.BytecodeString, _ctx.BytecodeKey); + var deserializer = new Deserializer(bytecode, _ctx); + + return deserializer.ReadFunction(); + } + + private void SolveKeys() + { + using var L = new Lua(openLibs: false); + + if (_ctx.KeyExpressions.Count == 2) + { + var code = $"return {PrettyPrinter.AsString(_ctx.KeyExpressions.First())}"; + _ctx.ConstantKey = Convert.ToInt32(L.DoString(code)[0]); + } + + { + var code = $"return {PrettyPrinter.AsString(_ctx.KeyExpressions.Last())}"; + _ctx.BytecodeKey = Convert.ToInt32(L.DoString(code)[0]); + } + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/OpCodes.cs b/bot/src/Deobfuscation/OpCodes.cs new file mode 100644 index 0000000..e2f2ad7 --- /dev/null +++ b/bot/src/Deobfuscation/OpCodes.cs @@ -0,0 +1,651 @@ +using MoonsecDeobfuscator.Bytecode.Models; + +namespace MoonsecDeobfuscator.Deobfuscation; + +public static class OpCodes +{ + // https://github.com/Trollicus/ironbrew-2/tree/master/IronBrew2/Obfuscator/Opcodes + + public static readonly Dictionary?)> StaticOpcodes = new() + { + // MOVE A B R(A) := R(B) + // stk[inst[OP_A]] = stk[inst[OP_B]] + ["91909190"] = (OpCode.Move, null), + + // LOADK A Bx R(A) := Kst(Bx) + // stk(inst[OP_A], inst[OP_B]) + ["1419090"] = (OpCode.LoadK, instruction => instruction.B--), + + // LOADBOOL A B C R(A) := (Bool)B; if (C) PC++ + // stk[inst[OP_A]] = inst[OP_B] ~= 0 + ["91902690"] = (OpCode.LoadBool, null), + // stk[inst[OP_A]] = inst[OP_B] ~= 0; pc = pc + 1 + ["91902690291529"] = (OpCode.LoadBool, instruction => instruction.C = 1), + + // LOADNIL A B R(A) := ... := R(B) := nil + // for _302 = inst[OP_A], inst[OP_B] do stk[_302] = nil end + ["13909091"] = (OpCode.LoadNil, null), + + // GETUPVAL A B R(A) := UpValue[B] + // stk[inst[OP_A]] = upv[inst[OP_B]] + ["91909290"] = (OpCode.GetUpval, null), + + // GETGLOBAL A Bx R(A) := Gbl[Kst(Bx)] + // stk[inst[OP_A]] = env[inst[OP_B]] + ["91909390"] = (OpCode.GetGlobal, instruction => instruction.B--), + + // GETTABLE A B C R(A) := R(B)[RK(C)] + //stk[inst[OP_A]] = stk[inst[OP_B]][stk[inst[OP_C]]] + ["9190991909190"] = (OpCode.GetTable, null), + // stk[inst[OP_A]] = stk[inst[OP_B]][inst[OP_C]] + ["91909919090"] = (OpCode.GetTable, instruction => instruction.C += 255), + + // SETGLOBAL A Bx Gbl[Kst(Bx)] := R(A) + // env[inst[OP_B]] = stk[inst[OP_A]] + ["93909190"] = (OpCode.SetGlobal, instruction => instruction.B--), + + // SETUPVAL A B UpValue[B] := R(A) + // upv[inst[OP_B]] = stk[inst[OP_A]] + ["92909190"] = (OpCode.SetUpval, null), + + // SETTABLE A B C R(A)[RK(B)] := RK(C) + // stk[inst[OP_A]][stk[inst[OP_B]]] = stk[inst[OP_C]] + ["9919091909190"] = (OpCode.SetTable, null), + // stk[inst[OP_A]][stk[inst[OP_B]]] = inst[OP_C] + ["99190919090"] = (OpCode.SetTable, instruction => instruction.C += 255), + // stk[inst[OP_A]][inst[OP_B]] = stk[inst[OP_C]] + ["99190909190"] = (OpCode.SetTable, instruction => instruction.B += 255), + // stk[inst[OP_A]][inst[OP_B]] = inst[OP_C] + ["991909090"] = (OpCode.SetTable, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // NEWTABLE A B C R(A) := {} (size = B,C) + // stk[inst[OP_A]] = {} + ["919033"] = (OpCode.NewTable, null), + + // SELF A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] + /* + local _17 = inst[OP_A] + local _18 = stk[inst[OP_B]] + stk[_17 + 1] = _18 + stk[_17] = _18[inst[OP_C]] + */ + ["909190911591990"] = (OpCode.Self, instruction => instruction.C += 255), + /* + local _511 = inst[OP_A] + local _512 = stk[inst[OP_B]] + stk[_511 + 1] = _512 + stk[_511] = _512[stk[inst[OP_C]]] + */ + ["90919091159199190"] = (OpCode.Self, null), + + // ADD A B C R(A) := RK(B) + RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] + stk[inst[OP_C]] + ["91901591909190"] = (OpCode.Add, null), + // stk[inst[OP_A]] = stk[inst[OP_B]] + inst[OP_C] + ["919015919090"] = (OpCode.Add, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] + stk[inst[OP_C]] + ["919015909190"] = (OpCode.Add, instruction => instruction.B += 255), + // stk[inst[OP_A]] = inst[OP_B] + inst[OP_C] + ["9190159090"] = (OpCode.Add, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // SUB A B C R(A) := RK(B) – RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] - stk[inst[OP_C]] + ["91901691909190"] = (OpCode.Sub, null), + // stk[inst[OP_A]] = stk[inst[OP_B]] - inst[OP_C] + ["919016919090"] = (OpCode.Sub, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] - stk[inst[OP_C]] + ["919016909190"] = (OpCode.Sub, instruction => instruction.B += 255), + // stk[inst[OP_A]] = inst[OP_B] - inst[OP_C] + ["9190169090"] = (OpCode.Sub, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // MUL A B C R(A) := RK(B) * RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] * stk[inst[OP_C]] + ["91901791909190"] = (OpCode.Mul, null), + // stk[inst[OP_A]] = stk[inst[OP_B]] * inst[OP_C] + ["919017919090"] = (OpCode.Mul, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] * stk[inst[OP_C]] + ["919017909190"] = (OpCode.Mul, instruction => instruction.B += 255), + // stk[inst[OP_A]] = inst[OP_B] * inst[OP_C] + ["9190179090"] = (OpCode.Mul, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // DIV A B C R(A) := RK(B) / RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] / stk[inst[OP_C]] + ["91901891909190"] = (OpCode.Div, null), + //stk[inst[OP_A]] = stk[inst[OP_B]] / inst[OP_C] + ["919018919090"] = (OpCode.Div, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] / stk[inst[OP_C]] + ["919018909190"] = (OpCode.Div, instruction => instruction.B += 255), + // stk[inst[OP_A]] = inst[OP_B] / inst[OP_C] + ["9190189090"] = (OpCode.Div, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // MOD A B C R(A) := RK(B) % RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] % stk[inst[OP_C]] + ["91901991909190"] = (OpCode.Mod, null), + // stk[inst[OP_A]] = stk[inst[OP_B]] % inst[OP_C] + ["919019919090"] = (OpCode.Mod, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] % stk[inst[OP_C]] + ["919019909190"] = (OpCode.Mod, instruction => instruction.B += 255), + // stk[inst[OP_A]] = inst[OP_B] % inst[OP_C] + ["9190199090"] = (OpCode.Mod, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // POW A B C R(A) := RK(B) ^ RK(C) + // stk[inst[OP_A]] = stk[inst[OP_B]] ^ stk[inst[OP_C]] + ["91902091909190"] = (OpCode.Pow, null), + // stk[inst[OP_A]] = stk[inst[OP_B]] ^ inst[OP_C] + ["919020919090"] = (OpCode.Pow, instruction => instruction.C += 255), + // stk[inst[OP_A]] = inst[OP_B] ^ stk[inst[OP_C]] + ["919020909190"] = (OpCode.Pow, instruction => instruction.B += 255), + // // stk[inst[OP_A]] = inst[OP_B] ^ inst[OP_C] + ["9190209090"] = (OpCode.Pow, instruction => + { + instruction.B += 255; + instruction.C += 255; + }), + + // UNM A B R(A) := -R(B) + // stk[inst[OP_A]] = -stk[inst[OP_B]] + ["9190319190"] = (OpCode.Unm, null), + + // NOT A B R(A) := not R(B) + // stk[inst[OP_A]] = not stk[inst[OP_B]] + ["9190349190"] = (OpCode.Not, null), + + // LEN A B R(A) := length of R(B) + // stk[inst[OP_A]] = #stk[inst[OP_B]] + ["9190289190"] = (OpCode.Len, null), + + // CONCAT A B C R(A) := R(B).. ... ..R(C) + /* + local _216 = inst[OP_B] + local _217 = stk[_216] + for _218 = _216 + 1, inst[OP_C] do + _217 = _217 .. stk[_218] + end + stk[inst[OP_A]] = _217 + */ + ["909113159032919190"] = (OpCode.Concat, null), + + // JMP sBx PC += sBx + // pc = inst[OP_B] + ["2990"] = (OpCode.Jmp, instruction => instruction.B -= instruction.PC + 1), + + // EQ A B C if ((RK(B) == RK(C)) ~= A) then PC++ + // if stk[inst[OP_A]] == stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["101225919091902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + }), + // if stk[inst[OP_A]] == inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["1012259190902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + instruction.C += 255; + }), + // if inst[OP_A] == stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["1012259091902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + }), + // if inst[OP_A] == inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["10122590902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + instruction.C += 255; + }), + // if stk[inst[OP_A]] ~= stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["101226919091902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + }), + // if stk[inst[OP_A]] ~= inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["1012269190902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + instruction.C += 255; + }), + // if inst[OP_A] ~= stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["1012269091902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + }), + // if inst[OP_A] ~= inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["10122690902915292990"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + instruction.C += 255; + }), + // pc = ((stk[inst[OP_A]] == stk[inst[OP_C]]) and inst[OP_B]) or (1 + pc) + ["2936352591909190901529"] = (OpCode.Eq, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + }), + + // LT A B C if ((RK(B) < RK(C)) ~= A) then PC++ + // if stk[inst[OP_A]] < stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["101221919091902915292990"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + }), + // if inst[OP_A] < stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["1012219091902915292990"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + }), + // if stk[inst[OP_A]] < inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["1012219190902915292990"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + instruction.C += 255; + }), + // if inst[OP_A] < inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["10122190902915292990"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + instruction.C += 255; + }), + // if stk[inst[OP_A]] < stk[inst[OP_C]] then pc = inst[OP_B] else pc = pc + 1 end + ["101221919091902990291529"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + }), + // if inst[OP_A] < stk[inst[OP_C]] then pc = inst[OP_B] else pc = pc + 1 end + ["1012219091902990291529"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + }), + // if stk[inst[OP_A]] < inst[OP_C] then pc = inst[OP_B] else pc = pc + 1 end + ["1012219190902990291529"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + instruction.C += 255; + }), + // if inst[OP_A] < inst[OP_C] then pc = inst[OP_B] else pc = pc + 1 end + ["10122190902990291529"] = (OpCode.Lt, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + instruction.C += 255; + }), + + // LE A B C if ((RK(B) <= RK(C)) ~= A) then PC++ + // if stk[inst[OP_A]] <= stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["101223919091902915292990"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + }), + // if inst[OP_A] <= stk[inst[OP_C]] then pc = pc + 1 else pc = inst[OP_B] end + ["1012239091902915292990"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + }), + // if stk[inst[OP_A]] <= inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["1012239190902915292990"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A; + instruction.A = 0; + instruction.C += 255; + }), + // if inst[OP_A] <= inst[OP_C] then pc = pc + 1 else pc = inst[OP_B] end + ["10122390902915292990"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 0; + instruction.C += 255; + }), + // if stk[inst[OP_A]] <= stk[inst[OP_C]] then pc = inst[OP_B] else pc = pc + 1 end + ["101223919091902990291529"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + }), + // if stk[inst[OP_A]] <= inst[OP_C] then pc = inst[OP_B] else pc = pc + 1 end + ["1012239190902990291529"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A; + instruction.A = 1; + instruction.C += 255; + }), + // if inst[OP_A] <= stk[inst[OP_C]] then pc = inst[OP_B] else pc = pc + 1 end + ["1012239091902990291529"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + }), + // if inst[OP_A] <= inst[OP_C] then pc = inst[OP_B] else pc = pc + 1 end + ["10122390902990291529"] = (OpCode.Le, instruction => + { + instruction.B = instruction.A + 255; + instruction.A = 1; + instruction.C += 255; + }), + + // TEST A C if not (R(A) <=> C) then PC++ + // if stk[inst[OP_A]] then pc = pc + 1 else pc = inst[OP_B] end + ["101291902915292990"] = (OpCode.Test, instruction => + { + instruction.B = 0; + instruction.C = 0; + }), + // if not stk[inst[OP_A]] then pc = pc + 1 else pc = inst[OP_B] end + ["10123491902915292990"] = (OpCode.Test, instruction => + { + instruction.B = 0; + instruction.C = 1; + }), + + // TESTSET A B C if (R(B) <=> C) then R(A) := R(B) else PC++ + // local _3 = stk[inst[OP_C]] if _3 then pc = pc + 1 else stk[inst[OP_A]] = _3 pc = inst[OP_B] end + ["9190101229152991902990"] = (OpCode.TestSet, instruction => + { + instruction.B = instruction.C; + instruction.C = 0; + }), + // local _14 = stk[inst[OP_C]] if not _14 then pc = pc + 1 else stk[inst[OP_A]] = _14 pc = inst[OP_B] end + ["919010123429152991902990"] = (OpCode.TestSet, instruction => + { + instruction.B = instruction.C; + instruction.C = 1; + }), + + // CALL A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) + // stk[inst[OP_A]]() + ["149190"] = (OpCode.Call, null), + // local _52 = inst[OP_A]; stk[_52] = stk[_52](stk[_52 + 1]) + ["909114919115"] = (OpCode.Call, null), + // local _19 = inst[OP_A]; stk[_19] = stk[_19](unpack(stk, _19 + 1, inst[OP_B])) + ["9091149114511590"] = (OpCode.Call, instruction => instruction.B -= instruction.A - 1), + // local _354 = inst[OP_A]; stk[_354](stk[_354 + 1]) + ["9014919115"] = (OpCode.Call, null), + // local _194 = inst[OP_A]; stk[_194](unpack(stk, _194 + 1, inst[OP_B])) + ["90149114511590"] = (OpCode.Call, instruction => instruction.B -= instruction.A - 1), + // local _80 = inst[OP_A]; stk[_80] = stk[_80](unpack(stk, _80 + 1, top)) + ["9091149114511530"] = (OpCode.Call, null), + /* + local _324 = inst[OP_A] + local _325 = { + stk[_324](stk[_324 + 1]) + } + local _326 = 0 + for _327 = _324, inst[OP_C] do + _326 = _326 + 1 + stk[_327] = _325[_326] + end + */ + ["903314919115139015919"] = (OpCode.Call, instruction => instruction.C -= instruction.A - 2), + // local _85 = inst[OP_A]; stk[_85] = stk[_85]() + ["90911491"] = (OpCode.Call, null), + /* + local _75 = inst[OP_A] + local _76, _77 = _R(stk[_75]()) + top = (_77 + _75) - 1 + local _78 = 0 + for _79 = _75, top do + _78 = _78 + 1 + stk[_79] = _76[_78] + end + */ + ["90141491301615133015919"] = (OpCode.Call, null), + /* + local _63 = inst[OP_A] + local _64, _65 = _R(stk[_63](stk[_63 + 1])) + top = (_65 + _63) - 1 + local _66 = 0 + for _67 = _63, top do + _66 = _66 + 1 + stk[_67] = _64[_66] + end + */ + ["901414919115301615133015919"] = (OpCode.Call, instruction => instruction.B -= instruction.A - 1), + /* + local _423 = inst[OP_A] + local _424, _425 = _R(stk[_423](unpack(stk, _423 + 1, inst[OP_B]))) + top = (_425 + _423) - 1 + local _426 = 0 + for _427 = _423, top do + _426 = _426 + 1 + stk[_427] = _424[_426] + end + */ + ["9014149114511590301615133015919"] = (OpCode.Call, instruction => instruction.B -= instruction.A - 1), + // local _133 = inst[OP_A]; stk[_133](unpack(stk, _133 + 1, top)) + ["90149114511530"] = (OpCode.Call, null), + /* + local _57 = inst[OP_A] + local _58 = { + stk[_57](unpack(stk, _57 + 1, inst[OP_B])) + } + local _59 = 0 + for _60 = _57, inst[OP_C] do + _59 = _59 + 1 + stk[_60] = _58[_59] + end + */ + ["9033149114511590139015919"] = (OpCode.Call, instruction => + { + instruction.B -= instruction.A - 1; + instruction.C -= instruction.A - 2; + }), + /* + local _1066 = inst[OP_A] + local _1067 = { + stk[_1066](unpack(stk, _1066 + 1, top)) + } + local _1068 = 0 + for _1069 = _1066, inst[OP_C] do + _1068 = _1068 + 1 + stk[_1069] = _1067[_1068] + end + */ + ["9033149114511530139015919"] = (OpCode.Call, instruction => instruction.C -= instruction.A - 2), + /* + local _511 = inst[OP_A] + local _512 = { + stk[_511]() + } + local _513 = inst[OP_C] + local _514 = 0 + for _515 = _511, _513 do + _514 = _514 + 1 + stk[_515] = _512[_514] + end + */ + ["90331491901315919"] = (OpCode.Call, instruction => instruction.C -= instruction.A - 2), + /* + local _189 = inst[OP_A] + local _190, _191 = _R(stk[_189](unpack(stk, _189 + 1, top))) + top = (_191 + _189) - 1 + local _192 = 0 + for _193 = _189, top do + _192 = _192 + 1 + stk[_193] = _190[_192] + end + */ + ["9014149114511530301615133015919"] = (OpCode.Call, null), + + // TAILCALL A B C return R(A)(R(A+1), ... ,R(A+B-1)) + // local _64 = inst[OP_A]; do return stk[_64](unpack(stk, _64 + 1, inst[OP_B])) end + ["9027149114511590"] = (OpCode.TailCall, instruction => instruction.B -= instruction.A - 1), + // local _135 = inst[OP_A]; do return stk[_135](unpack(stk, _135 + 1, top)); end + ["9027149114511530"] = (OpCode.TailCall, null), + // do return stk[inst[OP_A]](); end + ["27149190"] = (OpCode.TailCall, null), + + // RETURN A B return R(A), ... ,R(A+B-2) + // do return; end + ["27"] = (OpCode.Return, null), + // do return stk[inst[OP_A]]; end + ["279190"] = (OpCode.Return, null), + // local _1003 = inst[OP_A]; do return unpack(stk, _1003, top); end + ["9027145130"] = (OpCode.Return, null), + // local _879 = inst[OP_A]; do return unpack(stk, _879, _879 + inst[OP_B]); end + ["902714511590"] = (OpCode.Return, instruction => instruction.B += 2), + // local _601 = inst[OP_A]; do return stk[_601], stk[_601 + 1]; end + ["9027919115"] = (OpCode.Return, null), + + /* + FORLOOP A sBx R(A) += R(A+2) + if R(A) 0 then + if _146 <= stk[_144 + 1] then + pc = inst[OP_B] + stk[_144 + 3] = _146 + end + elseif _146 >= stk[_144 + 1] then + pc = inst[OP_B] + stk[_144 + 3] = _146 + end + */ + ["909115159191101122102391152990911524911529909115"] = (OpCode.ForLoop, instruction => + instruction.B -= instruction.PC + 1), + + // FORPREP A sBx R(A) -= R(A+2); PC += sBx + /* + local _200 = inst[OP_A] + local _201 = stk[_200] + local _202 = stk[(_200 + 2)] + if (_202 > 0) then + if (_201 > stk[(_200 + 1)]) then + pc = inst[OP_B] + else + stk[(_200 + 3)] = _201 + end + elseif (_201 < stk[(_200 + 1)]) then + pc = inst[OP_B] + else + stk[(_200 + 3)] = _201 + end + */ + ["909191151011122210122291152990911521911529909115"] = (OpCode.ForPrep, instruction => + instruction.B -= instruction.PC + 2), + + /* + TFORLOOP A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); + if R(A+3) ~= nil then { + R(A+2) = R(A+3); + } else { + PC++; + } + */ + /* + local _180 = inst[OP_A] + local _181 = inst[OP_C] + local _182 = _180 + 2 + local _183 = { + stk[_180](stk[_180 + 1], stk[_182]) + } + for _184 = 1, _181 do + stk[_182 + _184] = _183[_184] + end + local _185 = _183[1] + if _185 then + stk[_182] = _185 + pc = inst[OP_B] + else + pc = pc + 1 + end + */ + ["909015331491911591139115991012912990291529"] = (OpCode.TForLoop, instruction => instruction.B = 0), + + // SETLIST A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B + // I know long table SETLIST is missing. + // local _273 = inst[OP_A]; local _275 = stk[_273]; for _277 = (_273 + 1), top do; table.insert(_275, stk[_277]); end + ["909113153014691"] = (OpCode.SetList, null), + // local _504 = inst[OP_A]; local _505 = stk[_504]; for _506 = (_504 + 1), inst[OP_B] do table.insert(_505, stk[_506]); end + ["909113159014691"] = (OpCode.SetList, instruction => instruction.B -= instruction.A), + + // CLOSE A close all variables in the stack up to (>=) R(A) + /* + local _277 = {} + for _278 = 1, #lupv do + local _279 = lupv[_278] + for _280 = 0, #_279 do + local _281 = _279[_280] + local _282 = _281[1] + local _283 = _281[2] + if (_282 == stk) and (_283 >= inst[OP_A]) then + _277[_283] = _282[_283] + _281[1] = _277 + end + end + end + */ + ["3313289132899910352512490999"] = (OpCode.Close, null), + + // CLOSURE A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) + /* + SNIP + */ + ["990331473333927999999913902915299291012259916331991633299152891901483"] = (OpCode.Closure, null), + // stk[inst[OP_A]] = wrap_proto(protos[inst[OP_B]], nil, env) + ["91901489903"] = (OpCode.Closure, null), + + // VARARG A B R(A), R(A+1), ..., R(A+B-1) = vararg + /* + local _273 = inst[OP_A] + top = ((_273 + varargz) - 1) + for _276 = _273, top do + local _274 = vararg[(_276 - _273)] + stk[_276] = _274 + end + */ + ["903016151330941691"] = (OpCode.VarArg, null), + /* + local _328 = inst[OP_A] + local _329 = inst[OP_B] + for _330 = _328, _329 do + stk[_330] = vararg[_330 - _328] + end + */ + ["909013919416"] = (OpCode.VarArg, instruction => instruction.B -= instruction.A - 1) + }; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Rewriters/ConstantFolder.cs b/bot/src/Deobfuscation/Rewriters/ConstantFolder.cs new file mode 100644 index 0000000..d0bdf4c --- /dev/null +++ b/bot/src/Deobfuscation/Rewriters/ConstantFolder.cs @@ -0,0 +1,68 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; + +namespace MoonsecDeobfuscator.Deobfuscation.Rewriters; + +public class ConstantFolder : AstRewriter +{ + private static Expression FoldUnaryExpression(UnaryExpression node) + { + if (CanFoldTableLen(node)) + return FoldTableLen(node); + + if (CanFoldNegation(node)) + return FoldNegation(node); + + return node; + } + + private static NumberLiteral FoldTableLen(UnaryExpression node) => new(((Table) node.Operand).Entries.Count); + + private static bool CanFoldTableLen(UnaryExpression node) + { + return node is { Operator: UnaryOperator.Length, Operand: Table table } + && table.Entries.All(entry => entry.Key == null && entry.Value is Literal and not Nil); + } + + private static NumberLiteral FoldNegation(UnaryExpression node) => new(-((NumberLiteral) node.Operand).Value); + + private static bool CanFoldNegation(UnaryExpression node) => + node is { Operator: UnaryOperator.Negate, Operand: NumberLiteral }; + + private static BinaryExpression NormalizeComparison(BinaryExpression node) + { + if (node is not { Left: NumberLiteral, Right: not NumberLiteral }) + return node; + + switch (node.Operator) + { + case BinaryOperator.Equals: + case BinaryOperator.NotEquals: + (node.Left, node.Right) = (node.Right, node.Left); + break; + case BinaryOperator.LessThan: + node.Operator = BinaryOperator.GreaterThan; + (node.Left, node.Right) = (node.Right, node.Left); + break; + case BinaryOperator.GreaterThan: + node.Operator = BinaryOperator.LessThan; + (node.Left, node.Right) = (node.Right, node.Left); + break; + case BinaryOperator.LessThanOrEquals: + node.Operator = BinaryOperator.GreaterThanOrEquals; + (node.Left, node.Right) = (node.Right, node.Left); + break; + case BinaryOperator.GreaterThanOrEquals: + node.Operator = BinaryOperator.LessThanOrEquals; + (node.Left, node.Right) = (node.Right, node.Left); + break; + } + + return node; + } + + public override Node Visit(BinaryExpression node) => NormalizeComparison(node); + + public override Node Visit(UnaryExpression node) => FoldUnaryExpression(node); +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Rewriters/ConstantReplacer.cs b/bot/src/Deobfuscation/Rewriters/ConstantReplacer.cs new file mode 100644 index 0000000..7ad861d --- /dev/null +++ b/bot/src/Deobfuscation/Rewriters/ConstantReplacer.cs @@ -0,0 +1,22 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; + +namespace MoonsecDeobfuscator.Deobfuscation.Rewriters; + +public class ConstantReplacer(Dictionary constants) : AstRewriter +{ + public override Node Visit(MemberAccess node) => + constants.TryGetValue(node.Key.Value, out var values) ? CreateReplacement(values) : node; + + private static Expression CreateReplacement(string[] values) + { + if (int.TryParse(values[0], out var result)) + return new NumberLiteral(result); + + Expression name = new Name(values[0]); + return values + .Skip(1) + .Aggregate(name, (acc, str) => new MemberAccess(acc, new Name(str))); + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Rewriters/ControlFlowSolver.cs b/bot/src/Deobfuscation/Rewriters/ControlFlowSolver.cs new file mode 100644 index 0000000..a77a4ae --- /dev/null +++ b/bot/src/Deobfuscation/Rewriters/ControlFlowSolver.cs @@ -0,0 +1,116 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Deobfuscation.Utils; + +namespace MoonsecDeobfuscator.Deobfuscation.Rewriters; + +public class ControlFlowSolver : AstRewriter +{ + public override Node Visit(Repeat node) => + node is { Condition: BooleanLiteral { Value: true } } ? CreateReplacement(node.Body) : node; + + public override Node Visit(NumericFor node) + { + var match = node is + { + Body.Statements: [If { IfClause.Body.Statements: [.., Break or Do] }, ..] or [.., Break or Do] + }; + + return match ? CreateReplacement(node.Body) : node; + } + + /* + FiveM does this shit + if (-3 ~= n) then + if (0 < n) then + r = f + goto omluRWOc + end + d = e + ::omluRWOc:: + else + */ + public override Node Visit(If node) => + node.IfClause.Body.Statements is [If, .., Label] ? CreateReplacement(node.IfClause.Body) : node; + + public override Node Visit(Block node) + { + RemoveStateMachines(node); + RemoveUnreachable(node); + return node; + } + + private static void RemoveUnreachable(Block node) + { + var statements = node.Statements; + var idx = statements.FindIndex(stat => stat is Do or Return or Break); + + if (idx != -1 && idx + 1 < statements.Count) + statements.RemoveRange(idx + 1, statements.Count - idx - 1); + } + + private static void RemoveStateMachines(Block node) + { + var stats = node.Statements; + var stateMachines = stats.Where(IsStateMachine).ToList(); + + if (stateMachines.Count == 0) + return; + + foreach (var stateMachine in stateMachines) + { + var idx = stats.IndexOf(stateMachine); + var stateName = GetStateName(stateMachine); + var tree = GetTree(stateMachine); + + var solved = new TreeSolver(tree, stateName).Solve() + .OrderBy(it => it.Key) + .SelectMany(it => it.Value.Statements); + + stats.RemoveAt(idx); + stats.InsertRange(idx, solved); + } + } + + private static If CreateReplacement(Block node) + { + var innerIf = (If) node.Statements[0]; + var ifBody = new Block(); + var elseBody = new Block(); + + ifBody.Statements.AddRange(innerIf.IfClause.Body.Statements + .TakeWhile(stat => stat is not (Break or Label or Goto))); + elseBody.Statements.AddRange(node.Statements + .Skip(1) + .TakeWhile(stat => stat is not (Break or Label or Goto))); + + var clause = new If.Clause(innerIf.IfClause.Condition, ifBody); + + return new If(clause, [], elseBody); + } + + private static bool IsStateMachine(Statement node) + { + if (node is While { Condition: BinaryExpression { Right: NumberLiteral { Value: -1 } } }) + return true; + + return node is NumericFor + { + InitialValue: NumberLiteral, + FinalValue: NumberLiteral, + Body.Statements: [If] + }; + } + + private static string GetStateName(Statement node) + { + return node is While w + ? ((Name) ((BinaryExpression) w.Condition).Left).Value + : ((NumericFor) node).IteratorName.Value; + } + + private static If GetTree(Statement node) => + (If) (node is While w ? w.Body.Statements[0] : ((NumericFor) node).Body.Statements[0]); +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Rewriters/HandlerRewriter.cs b/bot/src/Deobfuscation/Rewriters/HandlerRewriter.cs new file mode 100644 index 0000000..8f30c42 --- /dev/null +++ b/bot/src/Deobfuscation/Rewriters/HandlerRewriter.cs @@ -0,0 +1,194 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Deobfuscation.Rewriters; + +// Hyi vittu kehtaako tätä edes julkaista...? +public class HandlerRewriter : AstRewriter +{ + public override Node Visit(Call node) + { + var args = node.Arguments; + + // stk(_201, _200) => stk(inst[OP_A], inst[OP_B]) + if (node.Function is Name { Value: "stk" } && args is [Name name1, Name name2]) + { + var newArg1 = ReplaceWithElementAccess(name1); + var newArg2 = ReplaceWithElementAccess(name2); + + if (name1 != newArg1 || name2 != newArg2) + return new Call(node.Function, [newArg1, newArg2]); + } + + return node; + } + + public override Node Visit(ElementAccess node) + { + var newTable = ReplaceWithName(node.Table); + var newKey = ReplaceWithName(node.Key); + + /* + local _186 = _184[_185] => local _186 = inst[OP_A] + */ + if (node.Table != newTable || node.Key != newKey) + return new ElementAccess(newTable, newKey); + + /* + stk[_185] = _186 => stk[inst[OP_A]] = _186 + */ + newKey = ReplaceWithElementAccess(node.Key); + + if (node.Key != newKey) + return new ElementAccess(newTable, newKey); + + return node; + } + + + public override Node Visit(Block node) + { + var unused = node.Statements + .Where(stat => stat is LocalDeclare decl && ShouldRemoveDeclaration(decl)) + .ToHashSet(); + + if (unused.Count > 0) + { + node.Statements.RemoveAll(stat => unused.Contains(stat)); + + // make sure changes are detected + return new Block(node.Statements); + } + + return node; + } + + public override Node Visit(Assign node) + { + /* + _185 = OP_A => local _185 = OP_A + */ + if (ShouldLocalizeAssignment(node)) + { + var names = new NodeList(node.Variables.Select(name => (Name) name)); + return new LocalDeclare(names, node.Values); + } + + /* + stk[_186] = _185 => stk[_186] = stk[inst[OP_B]] + */ + if (node is { Variables: [ElementAccess], Values: [Name name] }) + { + var replacement = ReplaceWithElementAccess(name); + + if (replacement != name) + return new Assign(node.Variables, [replacement]); + } + + /* + local _275 = (((stk[inst[OP_A]] == stk[inst[OP_C]]) and inst[OP_B]) or (1 + pc)) + pc = _275 + + => pc = (((stk[inst[OP_A]] == stk[inst[OP_C]]) and inst[OP_B]) or (1 + pc)) + */ + if (node is { Variables: [Name], Values: [Name name1] }) + { + var newValue = ReplaceWithBinaryExpression(name1); + + if (name1 != newValue) + return new Assign(node.Variables, [newValue]); + } + + return node; + } + + + public override Node Visit(BinaryExpression node) + { + var newLeft = ReplaceWithElementAccess(node.Left); + var newRight = ReplaceWithElementAccess(node.Right); + + /* + (((_273 == _274) and inst[OP_B]) or (1 + _269)) => (((stk[inst[OP_A]] == stk[inst[OP_C]]) and inst[OP_B]) or (1 + _269)) + */ + if (node.Left != newLeft || node.Right != newRight) + return new BinaryExpression(node.Operator, newLeft, newRight); + + newLeft = ReplaceWithName(node.Left); + newRight = ReplaceWithName(node.Right); + + /* + (1 + _269) => (1 + pc) + */ + if (node.Left != newLeft || node.Right != newRight) + return new BinaryExpression(node.Operator, newLeft, newRight); + + return node; + } + + private bool ShouldRemoveDeclaration(LocalDeclare node) + { + if (node.Values.Count == 0) + return true; + + foreach (var name in node.Names) + { + var info = GetVariable(name.Value); + + if (info is { ReadCount: > 0 }) + return false; + } + + return true; + } + + private bool ShouldLocalizeAssignment(Assign node) + { + foreach (var variable in node.Variables) + { + if (variable is not Name name) + return false; + + var value = name.Value; + + if (!value.StartsWith('_')) + return false; + + if (GetVariable(value)!.DeclarationLocation != node) + return false; + } + + return true; + } + + private Expression ReplaceWithName(Expression node) + { + if (node is not Name name || !name.Value.StartsWith('_')) + return node; + + return GetVariable(name.Value) is { Value: Name } info + ? info.Value.Clone() + : node; + } + + private Expression ReplaceWithElementAccess(Expression node) + { + if (node is not Name name || !name.Value.StartsWith('_')) + return node; + + return GetVariable(name.Value) is { Value: ElementAccess { Table: Name, Key: Name }, ReadCount: 1 } info + ? info.Value.Clone() + : node; + } + + private Expression ReplaceWithBinaryExpression(Expression node) + { + if (node is not Name name || !name.Value.StartsWith('_')) + return node; + + return GetVariable(name.Value) is { Value: BinaryExpression, ReadCount: 1, AssignmentCount: 0 } info + ? info.Value.Clone() + : node; + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Utils/Extensions.cs b/bot/src/Deobfuscation/Utils/Extensions.cs new file mode 100644 index 0000000..1819e27 --- /dev/null +++ b/bot/src/Deobfuscation/Utils/Extensions.cs @@ -0,0 +1,34 @@ +namespace MoonsecDeobfuscator.Deobfuscation.Utils; + +public static class Extensions +{ + public static IEnumerable> WindowedByDiscardedPairs(this IEnumerable source, Func predicate) + { + using var e = source.GetEnumerator(); + + if (!e.MoveNext()) + yield break; + + var window = new List { e.Current }; + var previous = e.Current; + + while (e.MoveNext()) + { + var current = e.Current; + + if (predicate(previous, current)) + { + yield return window.Count > 1 ? [..window[..^1]] : []; + window.Clear(); + previous = default!; + continue; + } + + window.Add(current); + previous = current; + } + + if (window.Count > 0) + yield return [..window]; + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Utils/Matching.cs b/bot/src/Deobfuscation/Utils/Matching.cs new file mode 100644 index 0000000..8186e86 --- /dev/null +++ b/bot/src/Deobfuscation/Utils/Matching.cs @@ -0,0 +1,31 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Deobfuscation.Utils; + +public static class Matching +{ + public static bool IsEnumComparison(Expression node) => + node is BinaryExpression { Left: Name { Value: "enum" } }; + + public static bool IsInstAssign(Statement node) => node is Assign + { + Variables: [Name { Value: "inst" }], + Values: [ElementAccess { Table: Name { Value: "insts" } }] + }; + + public static bool IsPcIncrement(Statement node) => node is Assign + { + Variables: [Name { Value: "pc" }], + Values: + [ + BinaryExpression + { + Operator: BinaryOperator.Add, + Left: Name { Value: "pc" } or NumberLiteral, + Right: Name { Value: "pc" } or NumberLiteral + } + ] + }; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Utils/StringDecoding.cs b/bot/src/Deobfuscation/Utils/StringDecoding.cs new file mode 100644 index 0000000..aca965d --- /dev/null +++ b/bot/src/Deobfuscation/Utils/StringDecoding.cs @@ -0,0 +1,99 @@ +using System.Text; + +namespace MoonsecDeobfuscator.Deobfuscation.Utils; + +public static class StringDecoding +{ + public static byte[] DecodeEscape(string data) + { + var parts = data.Split('\\').Skip(1).ToArray(); + var bytes = new byte[parts.Length]; + + for (var i = 0; i < bytes.Length; i++) + bytes[i] = byte.Parse(parts[i]); + + return bytes; + } + + public static byte[] Decode(string data, int key) + { + using var decoded = new MemoryStream((data.Length - 16) / 2); + var chars = new Dictionary(); + + for (var i = 0; i < 16; i++) + chars[data[i]] = i; + + var len = data.Length; + var rkey = key; + + for (var i = 16; i < len; i += 2) + { + var c1 = data[i]; + var c2 = i + 1 < len ? data[i + 1] : '\0'; + + var i1 = chars.ContainsKey(c1) ? chars[c1] : 0; + var i2 = chars.ContainsKey(c2) ? chars[c2] : 0; + + decoded.WriteByte((byte) ((i1 * 16 + i2 + rkey) % 256)); + rkey += key; + } + + return decoded.ToArray(); + } + + public static Dictionary DecodeConstants(byte[] data) + { + var constants = new Dictionary(); + + using var stream = new MemoryStream(data); + using var reader = new BinaryReader(stream); + + while (true) + { + var control = reader.ReadByte(); + + if (control == 5) + break; + + if (control == 1) + control++; + + var size = reader.ReadByte(); + var first = Encoding.UTF8.GetString(reader.ReadBytes(size)); + + string[]? value = null; + + switch (control) + { + case 0: + var strSize = reader.ReadByte(); + var second = Encoding.UTF8.GetString(reader.ReadBytes(strSize)); + value = [first, second]; + break; + case 2: + case 4: + case 6: + value = [first]; + break; + } + + var key = Encoding.UTF8.GetString(reader.ReadBytes(8)); + constants[key] = value!; + } + + return constants; + } + + public static string DecodeConstant(int key, byte[] bytes) + { + if (!(bytes.Length > 1 && bytes[0] > 0x7F)) + return Encoding.UTF8.GetString(bytes); + + var newBytes = new byte[bytes.Length - 1]; + + for (var i = 1; i < bytes.Length; i++) + newBytes[i - 1] = (byte) ((bytes[i] + key) % 256); + + return Encoding.UTF8.GetString(newBytes); + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Utils/TreeSolver.cs b/bot/src/Deobfuscation/Utils/TreeSolver.cs new file mode 100644 index 0000000..cff7763 --- /dev/null +++ b/bot/src/Deobfuscation/Utils/TreeSolver.cs @@ -0,0 +1,207 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using QuikGraph; + +namespace MoonsecDeobfuscator.Deobfuscation.Utils; + +// Using QuikGraph is probably not necessary, but I built it this way because I assumed I would need QuikGraph for a control flow graph of the bytecode. +public class TreeSolver(If tree, string stateName) +{ + private enum EdgeType + { + Then, + Else + } + + private class Range(int min, int max) + { + public int Min = min; + public int Max = max; + } + + private class Vertex + { + public BinaryOperator? Operator; + public int? ConstantValue; + + public Range? Range; + public Block? Body; + } + + private readonly BidirectionalGraph> _graph = new(); + + public Dictionary Solve() + { + AddBranches(tree, null, EdgeType.Then); + SetRanges(); + ReduceRanges(); + RemoveUnreachable(); + + var result = new Dictionary(); + + foreach (var vertex in _graph.Vertices.Where(IsTerminal)) + { + var range = vertex.Range!; + + if (range.Min != range.Max) + throw new Exception("Failed to reduce range!"); + + result[range.Min] = vertex.Body!; + } + + return result; + } + + private void RemoveUnreachable() + { + var unreachable = _graph.Vertices + .Where(v => IsTerminal(v) && v.Range is { Min: < 0, Max: < 0 }) + .ToHashSet(); + + foreach (var vertex in unreachable) + _graph.RemoveVertex(vertex); + } + + private void ReduceRanges() + { + var vertices = _graph.Vertices.ToList(); + var root = vertices.First(v => _graph.InDegree(v) == 0); + var leafs = vertices.Where(IsTerminal); + + foreach (var leaf in leafs) + { + var range = leaf.Range!; + + for (var i = range.Min; i <= range.Max; i++) + { + if (HasValidPath(leaf, root, i)) + { + range.Min = range.Max = i; + break; + } + + if (i == range.Max) + range.Min = range.Max = -1; + } + } + } + + private bool HasValidPath(Vertex current, Vertex root, int state) + { + if (current == root) + return true; + + foreach (var edge in _graph.InEdges(current)) + { + var source = edge.Source; + + if (IsValidPath(source, edge, state) && HasValidPath(source, root, state)) + return true; + } + + return false; + } + + private static bool IsValidPath(Vertex vertex, TaggedEdge edge, int state) + { + var constant = (int) vertex.ConstantValue!; + var valid = vertex.Operator! switch + { + BinaryOperator.Equals => state == constant, + BinaryOperator.NotEquals => state != constant, + BinaryOperator.LessThanOrEquals => state <= constant, + BinaryOperator.GreaterThanOrEquals => state >= constant, + BinaryOperator.LessThan => state < constant, + BinaryOperator.GreaterThan => state > constant, + _ => throw new Exception("Invalid operator in IsValidPath!") + }; + + return edge.Tag == EdgeType.Then == valid; + } + + private void SetRanges() + { + foreach (var node in _graph.Vertices) + { + if (IsTerminal(node)) + continue; + + var edges = _graph.OutEdges(node).ToList(); + + if (edges.Count != 2) + throw new Exception($"Expected 2 edges but got {edges.Count}"); + + var thenEdge = edges.First(edge => edge.Tag == EdgeType.Then); + var elseEdge = edges.First(edge => edge.Tag == EdgeType.Else); + var ranges = ComputeRanges(node); + + var thenTarget = thenEdge.Target; + var elseTarget = elseEdge.Target; + + if (IsTerminal(thenTarget)) + thenTarget.Range = ranges.Then; + + if (IsTerminal(elseTarget)) + elseTarget.Range = ranges.Else; + } + } + + private static (Range Then, Range Else) ComputeRanges(Vertex v) + { + var c = (int) v.ConstantValue!; + + return v.Operator! switch + { + BinaryOperator.Equals => (new Range(c, c), new Range(Math.Max(c - 1, 0), c + 1)), + BinaryOperator.NotEquals => (new Range(Math.Max(c - 1, 0), c + 1), new Range(c, c)), + BinaryOperator.LessThan => (new Range(Math.Max(c - 1, 0), Math.Max(c - 1, 0)), new Range(c, c)), + BinaryOperator.GreaterThan => (new Range(c + 1, c + 1), new Range(c, c)), + BinaryOperator.LessThanOrEquals => (new Range(c, c), new Range(c + 1, c + 1)), + BinaryOperator.GreaterThanOrEquals => (new Range(c, c), new Range(Math.Max(c - 1, 0), Math.Max(c - 1, 0))), + _ => throw new Exception("Invalid operator in ComputeRanges!") + }; + } + + private void AddBranches(If branch, Vertex? source, EdgeType edgeType) + { + var condition = (BinaryExpression) branch.IfClause.Condition; + var node = new Vertex + { + Operator = condition.Operator, + ConstantValue = (int) ((NumberLiteral) condition.Right).Value + }; + + _graph.AddVertex(node); + + if (source != null) + _graph.AddEdge(new TaggedEdge(source, node, edgeType)); + + AddBranch(branch.IfClause.Body, node, EdgeType.Then); + AddBranch(branch.ElseBody!, node, EdgeType.Else); + } + + private void AddBranch(Block body, Vertex source, EdgeType edgeType) + { + if (TreeContinues(body)) + { + AddBranches((If) body.Statements[0], source, edgeType); + } + else + { + var leaf = new Vertex + { + Body = body, + }; + + _graph.AddVertex(leaf); + _graph.AddEdge(new TaggedEdge(source, leaf, edgeType)); + } + } + + private bool IsTerminal(Vertex vertex) => _graph.OutDegree(vertex) == 0; + + private bool TreeContinues(Block node) => + node.Statements is [If { IfClause.Condition: BinaryExpression { Left: Name name } }] && name.Value == stateName; +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Walkers/Analyzer.cs b/bot/src/Deobfuscation/Walkers/Analyzer.cs new file mode 100644 index 0000000..0d016f5 --- /dev/null +++ b/bot/src/Deobfuscation/Walkers/Analyzer.cs @@ -0,0 +1,168 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Deobfuscation.Bytecode; + +namespace MoonsecDeobfuscator.Deobfuscation.Walkers; + +public class Analyzer(Context ctx) : AstWalker +{ + private int _funcCounter; + + public override void Visit(LocalFunction node) + { + switch (_funcCounter++) + { + case 8: + GetProtoFormat(node); + break; + case 10: + IdentifyWrapProto(node); + break; + case 11: + IdentifyWrapper(node); + break; + } + + base.Visit(node); + } + + public override void Visit(Call node) + { + if (node.Arguments is [Name, StringLiteral @string]) + ctx.BytecodeString = @string.Value.Trim('"'); + + base.Visit(node); + } + + public override void Visit(BinaryExpression node) + { + if (node is { Operator: BinaryOperator.Add, Right: Call }) + { + ctx.KeyExpressions.Add(node); + return; + } + + base.Visit(node); + } + + public override void Visit(LocalDeclare node) + { + if (node is { Names: [Name name], Values: [Expression expression] }) + { + var info = GetVariable(name.Value); + + if (info is not { AssignmentCount: 0 }) + return; + + if (expression is NumberLiteral number) + { + switch ((int) number.Value) + { + case 1: + Identify(name.Value, "OP_ENUM"); + break; + case 2: + Identify(name.Value, "OP_A"); + break; + case 3: + Identify(name.Value, "OP_B"); + break; + case 4: + Identify(name.Value, "OP_C"); + break; + } + } + else if (expression is BinaryExpression { Left: Name { Value: "unpack" } }) + { + Identify(name.Value, "unpack"); + } + } + + base.Visit(node); + } + + private void GetProtoFormat(LocalFunction node) + { + foreach (var stat in node.Body.Statements) + { + if (stat is Assign) + { + ctx.ProtoFormat.Add(ProtoStep.NumParams); + } + else if (stat is NumericFor numericFor) + { + switch (numericFor.Body.Statements.Count) + { + case 1: + ctx.ProtoFormat.Add(ProtoStep.Functions); + break; + case 2: + ctx.ProtoFormat.Add(ProtoStep.Instructions); + break; + case 4: + GetConstantFormat(numericFor); + ctx.ProtoFormat.Add(ProtoStep.Constants); + break; + } + } + } + } + + private void GetConstantFormat(NumericFor node) + { + var values = node.Body.DescendantNodes() + .Where(it => it is BinaryExpression { Operator: BinaryOperator.Equals }) + .Select(it => (BinaryExpression) it) + .Select(it => (byte) ((NumberLiteral) it.Right).Value) + .ToList(); + + ctx.ConstantFormat[values[0]] = ProtoStep.BooleanConstant; + ctx.ConstantFormat[values[1]] = ProtoStep.NumberConstant; + ctx.ConstantFormat[values[2]] = ProtoStep.StringConstant; + } + + private void IdentifyWrapProto(LocalFunction node) + { + var names = node.Parameters.Names; + + Identify(node.Name.Value, "wrap_proto"); + Identify(names[0].Value, "proto"); + Identify(names[1].Value, "upv"); + Identify(names[2].Value, "env"); + } + + private void IdentifyWrapper(LocalFunction node) + { + var names = node.Body.ChildNodes() + .OfType() + .SelectMany(decl => decl.Names) + .ToList(); + + Identify(names[0].Value, "insts"); + Identify(names[1].Value, "protos"); + Identify(names[2].Value, "params"); + Identify(names[4].Value, "_R"); + Identify(names[5].Value, "pc"); + Identify(names[6].Value, "top"); + Identify(names[7].Value, "vararg"); + Identify(names[8].Value, "args"); + Identify(names[9].Value, "pcount"); + Identify(names[10].Value, "lupv"); + Identify(names[11].Value, "stk"); + Identify(names[13].Value, "varargz"); + Identify(names[14].Value, "inst"); + Identify(names[15].Value, "enum"); + + ctx.Wrapper = node; + ctx.VmTree = (If) node.DescendantNodes() + .First(n => n is If { IfClause.Condition: BinaryExpression { Left: Name name } } + && name.Value == names[15].Value); + } + + private void Identify(string name, string newName) + { + ctx.IdentifiedNames[name] = newName; + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Walkers/FingerprintGenerator.cs b/bot/src/Deobfuscation/Walkers/FingerprintGenerator.cs new file mode 100644 index 0000000..08cedbf --- /dev/null +++ b/bot/src/Deobfuscation/Walkers/FingerprintGenerator.cs @@ -0,0 +1,228 @@ +using System.Text; +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Deobfuscation.Walkers; + +public class FingerprintGenerator : AstWalker +{ + private enum Operation + { + InstRef, + StkRef, + UpvRef, + EnvRef, + VarArgRef, + UnpackRef, + InsertRef, + SetMetatableRef, + WrapProtoRef, + Access, + If, + ElseIf, + Else, + For, + Call, + Add, + Sub, + Mul, + Div, + Mod, + Pow, + LessThan, + GreaterThan, + LessThanOrEquals, + GreaterThanOrEquals, + Equals, + NotEquals, + Return, + Len, + PcRef, + TopRef, + Negate, + Concat, + Table, + Not, + And, + Or + } + + private readonly List _operations = []; + + public override void Visit(Name node) + { + switch (node.Value) + { + case "stk": + _operations.Add(Operation.StkRef); + break; + case "env": + _operations.Add(Operation.EnvRef); + break; + case "upv": + _operations.Add(Operation.UpvRef); + break; + case "inst": + _operations.Add(Operation.InstRef); + break; + case "vararg": + _operations.Add(Operation.VarArgRef); + break; + case "unpack": + _operations.Add(Operation.UnpackRef); + break; + case "setmetatable": + _operations.Add(Operation.SetMetatableRef); + break; + case "pc": + _operations.Add(Operation.PcRef); + break; + case "top": + _operations.Add(Operation.TopRef); + break; + case "wrap_proto": + _operations.Add(Operation.WrapProtoRef); + break; + } + } + + public override void Visit(MemberAccess node) + { + if (node is { Table: Name { Value: "table" }, Key.Value: "insert" }) + _operations.Add(Operation.InsertRef); + else + _operations.Add(Operation.Access); + + base.Visit(node); + } + + public override void Visit(ElementAccess node) + { + _operations.Add(Operation.Access); + base.Visit(node); + } + + public override void Visit(If node) + { + _operations.Add(Operation.If); + + foreach (var _ in node.ElseIfClauses) + _operations.Add(Operation.ElseIf); + + if (node.ElseBody != null) + _operations.Add(Operation.Else); + + base.Visit(node); + } + + public override void Visit(NumericFor node) + { + _operations.Add(Operation.For); + base.Visit(node); + } + + public override void Visit(Call node) + { + _operations.Add(Operation.Call); + base.Visit(node); + } + + public override void Visit(BinaryExpression node) + { + // Java switches are much better... + switch (node.Operator) + { + case BinaryOperator.Add: + _operations.Add(Operation.Add); + break; + case BinaryOperator.Sub: + _operations.Add(Operation.Sub); + break; + case BinaryOperator.Mul: + _operations.Add(Operation.Mul); + break; + case BinaryOperator.Div: + _operations.Add(Operation.Div); + break; + case BinaryOperator.Mod: + _operations.Add(Operation.Mod); + break; + case BinaryOperator.Pow: + _operations.Add(Operation.Pow); + break; + case BinaryOperator.LessThan: + _operations.Add(Operation.LessThan); + break; + case BinaryOperator.LessThanOrEquals: + _operations.Add(Operation.LessThanOrEquals); + break; + case BinaryOperator.GreaterThan: + _operations.Add(Operation.GreaterThan); + break; + case BinaryOperator.GreaterThanOrEquals: + _operations.Add(Operation.GreaterThanOrEquals); + break; + case BinaryOperator.Equals: + _operations.Add(Operation.Equals); + break; + case BinaryOperator.NotEquals: + _operations.Add(Operation.NotEquals); + break; + case BinaryOperator.Concat: + _operations.Add(Operation.Concat); + break; + case BinaryOperator.And: + _operations.Add(Operation.And); + break; + case BinaryOperator.Or: + _operations.Add(Operation.Or); + break; + } + + base.Visit(node); + } + + public override void Visit(UnaryExpression node) + { + switch (node.Operator) + { + case UnaryOperator.Length: + _operations.Add(Operation.Len); + break; + case UnaryOperator.Negate: + _operations.Add(Operation.Negate); + break; + case UnaryOperator.Not: + _operations.Add(Operation.Not); + break; + } + + base.Visit(node); + } + + public override void Visit(Return node) + { + _operations.Add(Operation.Return); + base.Visit(node); + } + + public override void Visit(Table node) + { + _operations.Add(Operation.Table); + base.Visit(node); + } + + public static string Generate(Block node) + { + var walker = new FingerprintGenerator(); + walker.Visit(node); + + var result = new StringBuilder(); + + foreach (var operation in walker._operations) + result.Append((int) operation); + + return result.ToString(); + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Walkers/Renamer.cs b/bot/src/Deobfuscation/Walkers/Renamer.cs new file mode 100644 index 0000000..1e68472 --- /dev/null +++ b/bot/src/Deobfuscation/Walkers/Renamer.cs @@ -0,0 +1,192 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Deobfuscation.Walkers; + +public class Renamer : AstWalker +{ + private readonly Dictionary _names; + private readonly Stack _scopes = []; + private int _counter; + + public Renamer(Dictionary names) + { + _names = names; + PushScope(); + } + + public Renamer() : this([]) + { + } + + private Scope PushScope() + { + var scope = new Scope(); + _scopes.Push(scope); + return scope; + } + + private void PopScope() + { + _scopes.Pop(); + } + + private void RenameAndDefine(Scope scope, Name name) + { + var newName = _names.TryGetValue(name.Value, out var n) ? n : $"_{_counter++}"; + scope.Define(name.Value, newName); + name.Value = newName; + } + + public override void Visit(LocalFunction node) + { + RenameAndDefine(_scopes.Peek(), node.Name); + var scope = PushScope(); + + foreach (var name in node.Parameters.Names) + RenameAndDefine(scope, name); + + Visit(node.Body); + PopScope(); + } + + public override void Visit(Function node) + { + RenameAndDefine(_scopes.Peek(), node.Name); + var scope = PushScope(); + + foreach (var name in node.Parameters.Names) + RenameAndDefine(scope, name); + + Visit(node.Body); + PopScope(); + } + + public override void Visit(AnonymousFunction node) + { + var scope = PushScope(); + + foreach (var name in node.Parameters.Names) + RenameAndDefine(scope, name); + + Visit(node.Body); + PopScope(); + } + + public override void Visit(GenericFor node) + { + var scope = PushScope(); + + foreach (var name in node.Names) + RenameAndDefine(scope, name); + + Visit(node.Body); + PopScope(); + } + + public override void Visit(NumericFor node) + { + Visit(node.InitialValue); + Visit(node.FinalValue); + + if (node.Step != null) + Visit(node.Step); + + RenameAndDefine(PushScope(), node.IteratorName); + Visit(node.Body); + PopScope(); + } + + public override void Visit(Repeat node) + { + PushScope(); + Visit(node.Body); + Visit(node.Condition); + PopScope(); + } + + public override void Visit(While node) + { + Visit(node.Condition); + PushScope(); + Visit(node.Body); + PopScope(); + } + + public override void Visit(Do node) + { + PushScope(); + Visit(node.Body); + PopScope(); + } + + public override void Visit(If node) + { + Visit(node.IfClause); + VisitList(node.ElseIfClauses); + + var elseBody = node.ElseBody; + + if (elseBody != null) + { + PushScope(); + Visit(elseBody); + PopScope(); + } + } + + public override void Visit(If.Clause node) + { + Visit(node.Condition); + PushScope(); + Visit(node.Body); + PopScope(); + } + + public override void Visit(LocalDeclare node) + { + VisitList(node.Values); + var scope = _scopes.Peek(); + + foreach (var name in node.Names) + RenameAndDefine(scope, name); + } + + public override void Visit(Assign node) + { + VisitList(node.Values); + VisitList(node.Variables); + } + + public override void Visit(Name node) + { + var value = node.Value; + + foreach (var scope in _scopes) + { + if (!scope.IsDefined(value)) + continue; + + node.Value = scope.GetNewName(value); + break; + } + } + + private class Scope + { + private readonly Dictionary> _variables = []; + + public void Define(string name, string newName) + { + if (!_variables.ContainsKey(name)) + _variables[name] = []; + + _variables[name].Push(newName); + } + + public bool IsDefined(string name) => _variables.ContainsKey(name); + + public string GetNewName(string name) => _variables[name].Peek(); + } +} \ No newline at end of file diff --git a/bot/src/Deobfuscation/Walkers/StringCollector.cs b/bot/src/Deobfuscation/Walkers/StringCollector.cs new file mode 100644 index 0000000..54b4958 --- /dev/null +++ b/bot/src/Deobfuscation/Walkers/StringCollector.cs @@ -0,0 +1,33 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; + +namespace MoonsecDeobfuscator.Deobfuscation.Walkers; + +public class StringCollector : AstWalker +{ + private readonly List<(int?, string)> _strings = []; + + public override void Visit(Call node) + { + if (node.Arguments is [NumberLiteral number, StringLiteral @string]) + _strings.Add(((int) number.Value, @string.Value[1..^1])); + + base.Visit(node); + } + + public override void Visit(StringLiteral node) + { + var value = node.Value; + + if (value.StartsWith("\"\\4\\8")) + _strings.Add((null, value[1..^1])); + } + + public static List<(int?, string)> Collect(Node node) + { + var walker = new StringCollector(); + walker.Visit(node); + return walker._strings; + } +} \ No newline at end of file diff --git a/bot/src/Program.cs b/bot/src/Program.cs new file mode 100644 index 0000000..4a31d43 --- /dev/null +++ b/bot/src/Program.cs @@ -0,0 +1,234 @@ +using Discord; +using Discord.WebSocket; +using Discord.Interactions; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; +using System.Text; +using System.Net; +using Microsoft.AspNetCore.Builder; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading; +using MoonsecDeobfuscator.Deobfuscation; +using MoonsecDeobfuscator.Bytecode.Models; + +namespace GalacticBytecodeBot +{ + public class Program + { + private DiscordSocketClient _client = null!; + private InteractionService _interactions = null!; + private IServiceProvider _services = null!; + + public static async Task Main(string[] args) + { + // Load environment variables + try { DotNetEnv.Env.Load(); } catch { Console.WriteLine("No .env file found, using environment variables."); } + + // Start health check server for Render + _ = StartHealthCheckServer(); + + await new Program().RunAsync(); + } + + private static async Task StartHealthCheckServer() + { + var portStr = Environment.GetEnvironmentVariable("PORT") ?? "3000"; + var builder = WebApplication.CreateBuilder(); + + // FIXED: Use UseSetting instead of UseUrls for .NET 9.0 + builder.WebHost.UseSetting("urls", $"http://0.0.0.0:{portStr}"); + + var app = builder.Build(); + app.MapGet("/", () => "MoonSec Bot is running."); + + Console.WriteLine($"🌐 Health check listening on port {portStr}"); + await app.RunAsync(); + } + + public async Task RunAsync() + { + _client = new DiscordSocketClient(new DiscordSocketConfig + { + GatewayIntents = GatewayIntents.Guilds | GatewayIntents.DirectMessages, + AlwaysDownloadUsers = true + }); + + _interactions = new InteractionService(_client.Rest); + + _services = new ServiceCollection() + .AddSingleton(_client) + .AddSingleton(_interactions) + .AddSingleton() + .BuildServiceProvider(); + + _client.Log += msg => { Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {msg}"); return Task.CompletedTask; }; + _client.Ready += ReadyAsync; + _client.InteractionCreated += HandleInteractionAsync; + + var token = Environment.GetEnvironmentVariable("DISCORD_TOKEN"); + if (string.IsNullOrEmpty(token)) + throw new Exception("DISCORD_TOKEN missing in environment variables"); + + await _client.LoginAsync(TokenType.Bot, token); + await _client.StartAsync(); + + await Task.Delay(-1); + } + + private async Task ReadyAsync() + { + await _interactions.AddModulesAsync(Assembly.GetEntryAssembly(), _services); + await _interactions.RegisterCommandsGloballyAsync(true); + + await _client.SetStatusAsync(UserStatus.Online); + await _client.SetActivityAsync(new Game("🌙 MoonSec → Medal Pipeline")); + Console.WriteLine($"✅ Bot connected as {_client.CurrentUser}"); + + if (!File.Exists("/app/medal")) + Console.WriteLine("⚠️ WARNING: Medal not found at /app/medal"); + else + Console.WriteLine("✅ Medal found at /app/medal"); + } + + private async Task HandleInteractionAsync(SocketInteraction interaction) + { + var context = new SocketInteractionContext(_client, interaction); + await _interactions.ExecuteCommandAsync(context, _services); + } + } + + public class DeobfuscationModule : InteractionModuleBase + { + private readonly DeobfuscationService _service; + + public DeobfuscationModule(DeobfuscationService service) + { + _service = service; + } + + [SlashCommand("deobfuscate", "Deobfuscates a MoonSec-protected Lua file")] + public async Task DeobfuscateCommand( + [Summary("file", "Lua or text file")] IAttachment file) + { + await DeferAsync(); + + if (!file.Filename.EndsWith(".lua") && !file.Filename.EndsWith(".txt") && + !file.Filename.EndsWith(".luau")) + { + await FollowupAsync("❌ Only `.lua`, `.luau` or `.txt` files are allowed."); + return; + } + + try + { + using var http = new HttpClient(); + var bytes = await http.GetByteArrayAsync(file.Url); + var sourceCode = Encoding.UTF8.GetString(bytes); + + // Step 1: Deobfuscate and create bytecode + await FollowupAsync("🔄 **Step 1/3:** Deobfuscating with MoonSec..."); + var bytecode = _service.GenerateBytecode(sourceCode); + + var tempBytecode = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.luac"); + await File.WriteAllBytesAsync(tempBytecode, bytecode); + + // Step 2: Decompile with Medal + await ModifyOriginalResponseAsync(msg => msg.Content = "🔄 **Step 2/3:** Decompiling with Medal..."); + var decompiled = await _service.DecompileWithMedal(tempBytecode); + + try { File.Delete(tempBytecode); } catch { } + + if (string.IsNullOrWhiteSpace(decompiled)) + { + await ModifyOriginalResponseAsync(msg => msg.Content = "❌ Medal failed to decompile."); + return; + } + + // Step 3: Send result - FIXED: Build after setting description + await ModifyOriginalResponseAsync(msg => msg.Content = "✅ **Step 3/3:** Sending result..."); + + var embedBuilder = new EmbedBuilder() + .WithTitle("✅ Deobfuscation Complete") + .WithColor(Color.Green) + .WithFooter($"Processed by {Context.User.Username}"); + + if (decompiled.Length > 2000) + { + // Send as file + await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(decompiled)); + await FollowupWithFileAsync(stream, "decompiled.lua", + text: $"{Context.User.Mention} here is your decompiled code:", + embed: embedBuilder.Build()); + } + else + { + // Send in embed + embedBuilder.WithDescription($"```lua\n{decompiled}\n```"); + await FollowupAsync($"{Context.User.Mention}", embed: embedBuilder.Build()); + } + + await DeleteOriginalResponseAsync(); + } + catch (Exception ex) + { + Console.WriteLine($"❌ Error: {ex}"); + await FollowupAsync($"❌ Processing failed: `{ex.Message}`"); + } + } + } + + public class DeobfuscationService + { + public byte[] GenerateBytecode(string sourceCode) + { + var deob = new Deobfuscator(); + var result = deob.Deobfuscate(sourceCode); + + using var ms = new MemoryStream(); + var serializer = new MoonsecDeobfuscator.Deobfuscation.Bytecode.Serializer(ms); + serializer.Serialize(result); + return ms.ToArray(); + } + + public async Task DecompileWithMedal(string bytecodePath) + { + var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)); + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "/app/medal", + Arguments = $"\"{bytecodePath}\"", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + } + }; + + process.Start(); + var output = await process.StandardOutput.ReadToEndAsync(); + var error = await process.StandardError.ReadToEndAsync(); + + var exitTask = process.WaitForExitAsync(); + var timeoutTask = Task.Delay(TimeSpan.FromMinutes(3), cts.Token); + + if (await Task.WhenAny(exitTask, timeoutTask) == timeoutTask) + { + process.Kill(); + throw new TimeoutException("Medal timed out after 3 minutes"); + } + + if (process.ExitCode != 0) + throw new Exception($"Medal failed: {error}"); + + return output; + } + } +} diff --git a/bot/src/Syntax/Ast/Block.cs b/bot/src/Syntax/Ast/Block.cs new file mode 100644 index 0000000..50abba8 --- /dev/null +++ b/bot/src/Syntax/Ast/Block.cs @@ -0,0 +1,35 @@ +using System.Collections.Immutable; +using Antlr4.Runtime; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax; +using MoonsecDeobfuscator.Syntax.Parser; + +namespace MoonsecDeobfuscator.Ast; + +public class Block(NodeList statements) : Node +{ + public NodeList Statements { get; set; } = statements; + + public Block() : this([]) + { + } + + public override ImmutableList ChildNodes() => [..Statements]; + + public override Block Clone() => new(Statements.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); + + public static Block FromString(string code) + { + var lexer = new LuaLexer(CharStreams.fromString(code)); + var tokens = new CommonTokenStream(lexer); + + return new CstToAstVisitor().VisitBlock(new LuaParser(tokens).block()); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/AnonymousFunction.cs b/bot/src/Syntax/Ast/Expressions/AnonymousFunction.cs new file mode 100644 index 0000000..cad6966 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/AnonymousFunction.cs @@ -0,0 +1,24 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class AnonymousFunction(ParameterList parameters, Block body) : Expression +{ + public ParameterList Parameters { get; set; } = parameters; + public Block Body { get; set; } = body; + + public AnonymousFunction(Block body) : this(new ParameterList(), body) + { + } + + public override ImmutableList ChildNodes() => [Parameters, Body]; + + public override AnonymousFunction Clone() => new(Parameters.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/BinaryExpression.cs b/bot/src/Syntax/Ast/Expressions/BinaryExpression.cs new file mode 100644 index 0000000..89e6c06 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/BinaryExpression.cs @@ -0,0 +1,40 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public enum BinaryOperator +{ + Add, + Sub, + Mul, + Div, + Mod, + Pow, + Equals, + NotEquals, + LessThan, + GreaterThan, + LessThanOrEquals, + GreaterThanOrEquals, + And, + Or, + Concat +} + +public class BinaryExpression(BinaryOperator @operator, Expression left, Expression right) : Expression +{ + public BinaryOperator Operator { get; set; } = @operator; + public Expression Left { get; set; } = left; + public Expression Right { get; set; } = right; + + public override ImmutableList ChildNodes() => [Left, Right]; + + public override BinaryExpression Clone() => new(Operator, Left.Clone(), Right.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/Call.cs b/bot/src/Syntax/Ast/Expressions/Call.cs new file mode 100644 index 0000000..7e594ef --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/Call.cs @@ -0,0 +1,24 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class Call(Expression function, NodeList arguments) : Expression +{ + public Expression Function { get; set; } = function; + public NodeList Arguments { get; set; } = arguments; + + public Call(Expression function) : this(function, []) + { + } + + public override ImmutableList ChildNodes() => [Function, ..Arguments]; + + public override Call Clone() => new(Function.Clone(), Arguments.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/ElementAccess.cs b/bot/src/Syntax/Ast/Expressions/ElementAccess.cs new file mode 100644 index 0000000..c0f5643 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/ElementAccess.cs @@ -0,0 +1,20 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class ElementAccess(Expression table, Expression key) : Variable +{ + public Expression Table { get; set; } = table; + public Expression Key { get; set; } = key; + + public override ImmutableList ChildNodes() => [Table, Key]; + + public override ElementAccess Clone() => new(Table.Clone(), Key.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/Expression.cs b/bot/src/Syntax/Ast/Expressions/Expression.cs new file mode 100644 index 0000000..c0a7547 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/Expression.cs @@ -0,0 +1,6 @@ +namespace MoonsecDeobfuscator.Ast.Expressions; + +public abstract class Expression : Node +{ + public abstract override Expression Clone(); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/MemberAccess.cs b/bot/src/Syntax/Ast/Expressions/MemberAccess.cs new file mode 100644 index 0000000..1397d9c --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/MemberAccess.cs @@ -0,0 +1,20 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class MemberAccess(Expression table, Name key) : Variable +{ + public Expression Table { get; set; } = table; + public Name Key { get; set; } = key; + + public override ImmutableList ChildNodes() => [Table, Key]; + + public override MemberAccess Clone() => new(Table.Clone(), Key.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/MethodCall.cs b/bot/src/Syntax/Ast/Expressions/MethodCall.cs new file mode 100644 index 0000000..8f2d3af --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/MethodCall.cs @@ -0,0 +1,19 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class MethodCall(Expression function, Name methodName, NodeList arguments) : Call(function, arguments) +{ + public Name MethodName { get; set; } = methodName; + + public override ImmutableList ChildNodes() => [Function, MethodName, ..Arguments]; + + public override MethodCall Clone() => new(Function.Clone(), MethodName.Clone(), Arguments.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/Name.cs b/bot/src/Syntax/Ast/Expressions/Name.cs new file mode 100644 index 0000000..d745d0a --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/Name.cs @@ -0,0 +1,15 @@ +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class Name(string value) : Variable +{ + public string Value { get; set; } = value; + + public override Name Clone() => new(Value); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/Table.cs b/bot/src/Syntax/Ast/Expressions/Table.cs new file mode 100644 index 0000000..49757b1 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/Table.cs @@ -0,0 +1,44 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class Table(NodeList entries) : Expression +{ + public NodeList Entries { get; set; } = entries; + + public Table() : this([]) + { + } + + public override ImmutableList ChildNodes() => [..Entries]; + + public override Table Clone() => new(Entries.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); + + public class Entry(Expression? key, Expression value) : Expression + { + public Expression? Key { get; set; } = key; + public Expression Value { get; set; } = value; + + public Entry(Expression value) : this(null, value) + { + } + + public override ImmutableList ChildNodes() => Key != null ? [Key!, Value] : [Value]; + + public override Entry Clone() => new(Key?.Clone(), Value.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/UnaryExpression.cs b/bot/src/Syntax/Ast/Expressions/UnaryExpression.cs new file mode 100644 index 0000000..c9cffd4 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/UnaryExpression.cs @@ -0,0 +1,27 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Expressions; + +public enum UnaryOperator +{ + Not, + Length, + Negate +} + +public class UnaryExpression(UnaryOperator @operator, Expression operand) : Expression +{ + public Expression Operand { get; set; } = operand; + public UnaryOperator Operator { get; set; } = @operator; + + public override ImmutableList ChildNodes() => [Operand]; + + public override UnaryExpression Clone() => new(Operator, Operand.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/VarArg.cs b/bot/src/Syntax/Ast/Expressions/VarArg.cs new file mode 100644 index 0000000..585b99a --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/VarArg.cs @@ -0,0 +1,13 @@ +namespace MoonsecDeobfuscator.Ast.Expressions; + +public class VarArg : Expression +{ + public override VarArg Clone() => new(); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Expressions/Variable.cs b/bot/src/Syntax/Ast/Expressions/Variable.cs new file mode 100644 index 0000000..2227844 --- /dev/null +++ b/bot/src/Syntax/Ast/Expressions/Variable.cs @@ -0,0 +1,6 @@ +namespace MoonsecDeobfuscator.Ast.Expressions; + +public abstract class Variable : Expression +{ + public abstract override Variable Clone(); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Literals/BooleanLiteral.cs b/bot/src/Syntax/Ast/Literals/BooleanLiteral.cs new file mode 100644 index 0000000..0d71e88 --- /dev/null +++ b/bot/src/Syntax/Ast/Literals/BooleanLiteral.cs @@ -0,0 +1,15 @@ +namespace MoonsecDeobfuscator.Ast.Literals; + +public class BooleanLiteral(bool value) : Literal +{ + public bool Value { get; set; } = value; + + public override BooleanLiteral Clone() => new(Value); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Literals/Literal.cs b/bot/src/Syntax/Ast/Literals/Literal.cs new file mode 100644 index 0000000..969b34e --- /dev/null +++ b/bot/src/Syntax/Ast/Literals/Literal.cs @@ -0,0 +1,8 @@ +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Literals; + +public abstract class Literal : Expression +{ + public abstract override Literal Clone(); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Literals/Nil.cs b/bot/src/Syntax/Ast/Literals/Nil.cs new file mode 100644 index 0000000..0954fef --- /dev/null +++ b/bot/src/Syntax/Ast/Literals/Nil.cs @@ -0,0 +1,13 @@ +namespace MoonsecDeobfuscator.Ast.Literals; + +public class Nil : Literal +{ + public override Nil Clone() => new(); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Literals/NumberLiteral.cs b/bot/src/Syntax/Ast/Literals/NumberLiteral.cs new file mode 100644 index 0000000..e8e296d --- /dev/null +++ b/bot/src/Syntax/Ast/Literals/NumberLiteral.cs @@ -0,0 +1,15 @@ +namespace MoonsecDeobfuscator.Ast.Literals; + +public class NumberLiteral(double value) : Literal +{ + public double Value { get; set; } = value; + + public override NumberLiteral Clone() => new(Value); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Literals/StringLiteral.cs b/bot/src/Syntax/Ast/Literals/StringLiteral.cs new file mode 100644 index 0000000..758e93c --- /dev/null +++ b/bot/src/Syntax/Ast/Literals/StringLiteral.cs @@ -0,0 +1,15 @@ +namespace MoonsecDeobfuscator.Ast.Literals; + +public class StringLiteral(string value) : Literal +{ + public string Value { get; set; } = value; + + public override StringLiteral Clone() => new(Value); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Node.cs b/bot/src/Syntax/Ast/Node.cs new file mode 100644 index 0000000..744172c --- /dev/null +++ b/bot/src/Syntax/Ast/Node.cs @@ -0,0 +1,25 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast; + +public abstract class Node +{ + public virtual ImmutableList ChildNodes() => []; + + public IEnumerable DescendantNodes() + { + foreach (var child in ChildNodes()) + { + yield return child; + + foreach (var descendant in child.DescendantNodes()) + yield return descendant; + } + } + + public abstract Node Clone(); + + public abstract void Accept(AstWalker visitor); + + public abstract Node Accept(AstRewriter visitor); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/NodeList.cs b/bot/src/Syntax/Ast/NodeList.cs new file mode 100644 index 0000000..d4f6464 --- /dev/null +++ b/bot/src/Syntax/Ast/NodeList.cs @@ -0,0 +1,26 @@ +namespace MoonsecDeobfuscator.Ast; + +public class NodeList : List where TNode : Node +{ + public NodeList() + { + } + + public NodeList(int capacity) : base(capacity) + { + } + + public NodeList(IEnumerable collection) : base(collection) + { + } + + public NodeList Clone() + { + var newList = new NodeList(Count); + + foreach (var element in this) + newList.Add((TNode) element.Clone()); + + return newList; + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/ParameterList.cs b/bot/src/Syntax/Ast/ParameterList.cs new file mode 100644 index 0000000..07e8954 --- /dev/null +++ b/bot/src/Syntax/Ast/ParameterList.cs @@ -0,0 +1,25 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast; + +public class ParameterList(NodeList names, bool isVarArg = false) : Node +{ + public NodeList Names { get; set; } = names; + public bool IsVarArg { get; set; } = isVarArg; + + public ParameterList() : this([]) + { + } + + public override ImmutableList ChildNodes() => [..Names]; + + public override ParameterList Clone() => new(Names.Clone(), IsVarArg); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/PrettyPrinter.cs b/bot/src/Syntax/Ast/PrettyPrinter.cs new file mode 100644 index 0000000..860a7a8 --- /dev/null +++ b/bot/src/Syntax/Ast/PrettyPrinter.cs @@ -0,0 +1,424 @@ +using System.Text; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Ast; + +public class PrettyPrinter : AstWalker +{ + private readonly StringBuilder _builder = new(); + private int _depth; + + public static void Print(Node node) + { + var visitor = new PrettyPrinter(); + node.Accept(visitor); + Console.WriteLine(visitor._builder); + } + + public static string AsString(Node node) + { + var visitor = new PrettyPrinter(); + node.Accept(visitor); + return visitor._builder.ToString(); + } + + private void Indent() + { + for (var i = 0; i < _depth * 4; i++) + _builder.Append(' '); + } + + public override void Visit(Name node) + { + _builder.Append(node.Value); + } + + public override void Visit(ElementAccess node) + { + Visit(node.Table); + _builder.Append('['); + Visit(node.Key); + _builder.Append(']'); + } + + public override void Visit(MemberAccess node) + { + Visit(node.Table); + _builder.Append($".{node.Key.Value}"); + } + + public override void Visit(BinaryExpression node) + { + _builder.Append('('); + Visit(node.Left); + _builder.Append(OperatorToString(node.Operator)); + Visit(node.Right); + _builder.Append(')'); + } + + public override void Visit(UnaryExpression node) + { + _builder.Append(OperatorToString(node.Operator)); + Visit(node.Operand); + } + + public override void Visit(Call node) + { + var needsPar = node.Function is not Variable; + + if (needsPar) + _builder.Append('('); + + Visit(node.Function); + + if (needsPar) + _builder.Append(')'); + + _builder.Append('('); + VisitList(node.Arguments); + _builder.Append(')'); + } + + public override void Visit(MethodCall node) + { + var needsPar = node.Function is not Variable; + + if (needsPar) + _builder.Append('('); + + Visit(node.Function); + + if (needsPar) + _builder.Append(')'); + + _builder.Append($":{node.MethodName.Value}"); + _builder.Append('('); + VisitList(node.Arguments); + _builder.Append(')'); + } + + public override void Visit(Table node) + { + var entries = node.Entries; + + if (entries.Count == 0) + { + _builder.Append("{}"); + } + else + { + _builder.AppendLine("{"); + _depth++; + + for (var i = 0; i < entries.Count; i++) + { + Indent(); + Visit(entries[i]); + + if (i + 1 < entries.Count) + _builder.Append(", "); + + _builder.AppendLine(); + } + + _depth--; + Indent(); + _builder.Append('}'); + } + } + + public override void Visit(Table.Entry node) + { + var key = node.Key; + + if (key != null) + { + if (key is Name name) + { + _builder.Append($"{name.Value} = "); + } + else + { + _builder.Append('['); + Visit(key); + _builder.Append("] = "); + } + } + + Visit(node.Value); + } + + public override void Visit(AnonymousFunction node) + { + _builder.Append("function"); + Visit(node.Parameters); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(VarArg node) + { + _builder.Append("..."); + } + + public override void Visit(ExpressionStatement node) + { + Visit(node.Expression); + } + + public override void Visit(While node) + { + _builder.Append("while "); + Visit(node.Condition); + _builder.AppendLine(" do"); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(LocalDeclare node) + { + _builder.Append("local "); + VisitList(node.Names); + + if (node.Values.Count > 0) + { + _builder.Append(" = "); + VisitList(node.Values); + } + } + + public override void Visit(Assign node) + { + VisitList(node.Variables); + _builder.Append(" = "); + VisitList(node.Values); + } + + public override void Visit(GenericFor node) + { + _builder.Append("for "); + VisitList(node.Names); + _builder.Append(" in "); + VisitList(node.Expressions); + _builder.AppendLine(" do"); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(NumericFor node) + { + _builder.Append($"for {node.IteratorName.Value} = "); + Visit(node.InitialValue); + _builder.Append(", "); + Visit(node.FinalValue); + + if (node.Step != null) + { + _builder.Append(", "); + Visit(node.Step); + } + + _builder.AppendLine(" do"); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(If node) + { + _builder.Append("if "); + Visit(node.IfClause); + + foreach (var elseIf in node.ElseIfClauses) + { + Indent(); + _builder.Append("elseif "); + Visit(elseIf); + } + + if (node.ElseBody != null) + { + Indent(); + _builder.AppendLine("else"); + _depth++; + Visit(node.ElseBody); + _depth--; + } + + Indent(); + _builder.Append("end"); + } + + public override void Visit(If.Clause node) + { + Visit(node.Condition); + _builder.AppendLine(" then"); + _depth++; + Visit(node.Body); + _depth--; + } + + public override void Visit(LocalFunction node) + { + _builder.Append($"local function {node.Name.Value}"); + Visit(node.Parameters); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(Function node) + { + _builder.Append($"function {node.Name.Value}"); + Visit(node.Parameters); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(Break node) + { + _builder.Append("break"); + } + + public override void Visit(Do node) + { + _builder.AppendLine("do"); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("end"); + } + + public override void Visit(Repeat node) + { + _builder.AppendLine("repeat"); + _depth++; + Visit(node.Body); + _depth--; + Indent(); + _builder.Append("until "); + Visit(node.Condition); + } + + public override void Visit(Return node) + { + _builder.Append("return"); + + if (node.Values.Count > 0) + { + _builder.Append(' '); + VisitList(node.Values); + } + } + + public override void Visit(ParameterList node) + { + _builder.Append('('); + + VisitList(node.Names); + + if (node.IsVarArg) + _builder.Append(node.Names.Count == 0 ? "..." : ", ..."); + + _builder.Append(')'); + _builder.AppendLine(); + } + + public override void Visit(StringLiteral node) + { + _builder.Append(node.Value); + } + + public override void Visit(NumberLiteral node) + { + _builder.Append(node.Value); + } + + public override void Visit(BooleanLiteral node) + { + _builder.Append(node.Value.ToString().ToLower()); + } + + public override void Visit(Nil node) + { + _builder.Append("nil"); + } + + public override void Visit(Block node) + { + foreach (var statement in node.Statements) + { + Indent(); + Visit(statement); + _builder.AppendLine(); + } + } + + public override void Visit(Goto node) + { + _builder.Append($"goto {node.Name.Value}"); + } + + public override void Visit(Label node) + { + _builder.Append($"::{node.Name.Value}::"); + } + + protected override void VisitList(NodeList list) + { + for (var i = 0; i < list.Count; i++) + { + Visit(list[i]); + + if (i + 1 < list.Count) + _builder.Append(", "); + } + } + + private static string OperatorToString(BinaryOperator @operator) => @operator switch + { + BinaryOperator.Add => " + ", + BinaryOperator.Sub => " - ", + BinaryOperator.Mul => " * ", + BinaryOperator.Div => " / ", + BinaryOperator.Mod => " % ", + BinaryOperator.Pow => " ^ ", + BinaryOperator.Equals => " == ", + BinaryOperator.NotEquals => " ~= ", + BinaryOperator.LessThan => " < ", + BinaryOperator.GreaterThan => " > ", + BinaryOperator.LessThanOrEquals => " <= ", + BinaryOperator.GreaterThanOrEquals => " >= ", + BinaryOperator.And => " and ", + BinaryOperator.Or => " or ", + BinaryOperator.Concat => " .. ", + _ => " ?? " + }; + + private static string OperatorToString(UnaryOperator @operator) => @operator switch + { + UnaryOperator.Not => "not ", + UnaryOperator.Length => "#", + UnaryOperator.Negate => "-", + _ => "??" + }; +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Assign.cs b/bot/src/Syntax/Ast/Statements/Assign.cs new file mode 100644 index 0000000..bd0a1b3 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Assign.cs @@ -0,0 +1,21 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Assign(NodeList variables, NodeList values) : Statement +{ + public NodeList Variables { get; set; } = variables; + public NodeList Values { get; set; } = values; + + public override ImmutableList ChildNodes() => [..Variables, ..Values]; + + public override Assign Clone() => new(Variables.Clone(), Values.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Break.cs b/bot/src/Syntax/Ast/Statements/Break.cs new file mode 100644 index 0000000..6345f90 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Break.cs @@ -0,0 +1,13 @@ +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Break : Statement +{ + public override Break Clone() => new(); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Do.cs b/bot/src/Syntax/Ast/Statements/Do.cs new file mode 100644 index 0000000..1e2551b --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Do.cs @@ -0,0 +1,19 @@ +using System.Collections.Immutable; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Do(Block body) : Statement +{ + public Block Body { get; set; } = body; + + public override ImmutableList ChildNodes() => [Body]; + + public override Do Clone() => new(Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/ExpressionStatement.cs b/bot/src/Syntax/Ast/Statements/ExpressionStatement.cs new file mode 100644 index 0000000..6c0ab8c --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/ExpressionStatement.cs @@ -0,0 +1,20 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class ExpressionStatement(Expression expression) : Statement +{ + public Expression Expression { get; set; } = expression; + + public override ImmutableList ChildNodes() => [Expression]; + + public override ExpressionStatement Clone() => new(Expression.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Function.cs b/bot/src/Syntax/Ast/Statements/Function.cs new file mode 100644 index 0000000..f929afb --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Function.cs @@ -0,0 +1,26 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Function(Name name, ParameterList parameters, Block body) : Statement +{ + public Name Name { get; set; } = name; + public ParameterList Parameters { get; set; } = parameters; + public Block Body { get; set; } = body; + + public Function(Name name, Block body) : this(name, new ParameterList(), body) + { + } + + public override ImmutableList ChildNodes() => [Name, Parameters, Body]; + + public override Function Clone() => new(Name.Clone(), Parameters.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/GenericFor.cs b/bot/src/Syntax/Ast/Statements/GenericFor.cs new file mode 100644 index 0000000..9e6a1ee --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/GenericFor.cs @@ -0,0 +1,22 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class GenericFor(NodeList names, NodeList expressions, Block body) : Statement +{ + public NodeList Names { get; set; } = names; + public NodeList Expressions { get; set; } = expressions; + public Block Body { get; set; } = body; + + public override ImmutableList ChildNodes() => [..Names, ..Expressions, Body]; + + public override GenericFor Clone() => new(Names.Clone(), Expressions.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Goto.cs b/bot/src/Syntax/Ast/Statements/Goto.cs new file mode 100644 index 0000000..f98acdf --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Goto.cs @@ -0,0 +1,20 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Goto(Name name) : Statement +{ + public Name Name { get; set; } = name; + + public override ImmutableList ChildNodes() => [Name]; + + public override Goto Clone() => new(Name.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/If.cs b/bot/src/Syntax/Ast/Statements/If.cs new file mode 100644 index 0000000..28d9327 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/If.cs @@ -0,0 +1,44 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class If(If.Clause ifClause, NodeList elseIfClauses, Block? elseBody = null) : Statement +{ + public Clause IfClause { get; set; } = ifClause; + public NodeList ElseIfClauses { get; set; } = elseIfClauses; + public Block? ElseBody { get; set; } = elseBody; + + public If(Clause ifClause) : this(ifClause, []) + { + } + + public override ImmutableList ChildNodes() => + ElseBody != null ? [IfClause, ..ElseIfClauses, ElseBody] : [IfClause, ..ElseIfClauses]; + + public override If Clone() => new(IfClause.Clone(), ElseIfClauses.Clone(), ElseBody?.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); + + public class Clause(Expression condition, Block body) : Node + { + public Expression Condition { get; set; } = condition; + public Block Body { get; set; } = body; + + public override ImmutableList ChildNodes() => [Condition, Body]; + + public override Clause Clone() => new(Condition.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Label.cs b/bot/src/Syntax/Ast/Statements/Label.cs new file mode 100644 index 0000000..4c2dfa9 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Label.cs @@ -0,0 +1,20 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Label(Name name) : Statement +{ + public Name Name { get; set; } = name; + + public override ImmutableList ChildNodes() => [Name]; + + public override Label Clone() => new(Name.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/LocalDeclare.cs b/bot/src/Syntax/Ast/Statements/LocalDeclare.cs new file mode 100644 index 0000000..43e94df --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/LocalDeclare.cs @@ -0,0 +1,25 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class LocalDeclare(NodeList names, NodeList values) : Statement +{ + public NodeList Names { get; set; } = names; + public NodeList Values { get; set; } = values; + + public LocalDeclare(NodeList names) : this(names, []) + { + } + + public override ImmutableList ChildNodes() => [..Names, ..Values]; + + public override LocalDeclare Clone() => new(Names.Clone(), Values.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/LocalFunction.cs b/bot/src/Syntax/Ast/Statements/LocalFunction.cs new file mode 100644 index 0000000..acffcc4 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/LocalFunction.cs @@ -0,0 +1,26 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class LocalFunction(Name name, ParameterList parameters, Block body) : Statement +{ + public Name Name { get; set; } = name; + public ParameterList Parameters { get; set; } = parameters; + public Block Body { get; set; } = body; + + public LocalFunction(Name name, Block body) : this(name, new ParameterList(), body) + { + } + + public override ImmutableList ChildNodes() => [Name, Parameters, Body]; + + public override LocalFunction Clone() => new(Name.Clone(), Parameters.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/NumericFor.cs b/bot/src/Syntax/Ast/Statements/NumericFor.cs new file mode 100644 index 0000000..67030b1 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/NumericFor.cs @@ -0,0 +1,44 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class NumericFor : Statement +{ + public Name IteratorName { get; set; } + public Expression InitialValue { get; set; } + public Expression FinalValue { get; set; } + public Expression? Step { get; set; } + public Block Body { get; set; } + + public NumericFor(Name iteratorName, Expression initialValue, Expression finalValue, Expression? step, Block body) + { + IteratorName = iteratorName; + InitialValue = initialValue; + FinalValue = finalValue; + Step = step; + Body = body; + } + + public NumericFor(Name iteratorName, Expression initialValue, Expression finalValue, Block body) + { + IteratorName = iteratorName; + InitialValue = initialValue; + FinalValue = finalValue; + Body = body; + } + + public override ImmutableList ChildNodes() => Step != null + ? [IteratorName, InitialValue, FinalValue, Step!, Body] + : [IteratorName, InitialValue, FinalValue, Body]; + + public override NumericFor Clone() => + new(IteratorName.Clone(), InitialValue.Clone(), FinalValue.Clone(), Step?.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Repeat.cs b/bot/src/Syntax/Ast/Statements/Repeat.cs new file mode 100644 index 0000000..e0244e3 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Repeat.cs @@ -0,0 +1,21 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Repeat(Block body, Expression condition) : Statement +{ + public Block Body { get; set; } = body; + public Expression Condition { get; set; } = condition; + + public override ImmutableList ChildNodes() => [Body, Condition]; + + public override Repeat Clone() => new(Body.Clone(), Condition.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Return.cs b/bot/src/Syntax/Ast/Statements/Return.cs new file mode 100644 index 0000000..8ce2125 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Return.cs @@ -0,0 +1,24 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class Return(NodeList values) : Statement +{ + public NodeList Values { get; set; } = values; + + public Return() : this([]) + { + } + + public override ImmutableList ChildNodes() => [..Values]; + + public override Return Clone() => new(Values.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/Statement.cs b/bot/src/Syntax/Ast/Statements/Statement.cs new file mode 100644 index 0000000..cd18851 --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/Statement.cs @@ -0,0 +1,6 @@ +namespace MoonsecDeobfuscator.Ast.Statements; + +public abstract class Statement : Node +{ + public abstract override Statement Clone(); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Statements/While.cs b/bot/src/Syntax/Ast/Statements/While.cs new file mode 100644 index 0000000..f3b0c5e --- /dev/null +++ b/bot/src/Syntax/Ast/Statements/While.cs @@ -0,0 +1,21 @@ +using System.Collections.Immutable; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Ast.Statements; + +public class While(Expression condition, Block body) : Statement +{ + public Expression Condition { get; set; } = condition; + public Block Body { get; set; } = body; + + public override ImmutableList ChildNodes() => [Condition, Body]; + + public override While Clone() => new(Condition.Clone(), Body.Clone()); + + public override void Accept(AstWalker visitor) + { + visitor.Visit(this); + } + + public override Node Accept(AstRewriter visitor) => visitor.Visit(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/AstRewriter.cs b/bot/src/Syntax/Ast/Visitors/AstRewriter.cs new file mode 100644 index 0000000..85230db --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/AstRewriter.cs @@ -0,0 +1,90 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax.Semantic; + +namespace MoonsecDeobfuscator.Ast; + +public abstract class AstRewriter +{ + public SymbolTable? SymbolTable; + + public void Rewrite(Node node, Order order, bool symbols = false, bool fixedPoint = false) + { + IRewriteDispatch disp = order == Order.PostOrder + ? new PostOrderRewriteDispatch(this) + : new PreOrderRewriteDispatch(this); + + disp.Rewrite(node, symbols, fixedPoint); + } + + protected VariableInfo? GetVariable(string name) => SymbolTable?.GetVariable(name); + + public virtual Node Visit(Name node) => node; + + public virtual Node Visit(ElementAccess node) => node; + + public virtual Node Visit(MemberAccess node) => node; + + public virtual Node Visit(BinaryExpression node) => node; + + public virtual Node Visit(UnaryExpression node) => node; + + public virtual Node Visit(Call node) => node; + + public virtual Node Visit(MethodCall node) => node; + + public virtual Node Visit(Table node) => node; + + public virtual Node Visit(Table.Entry node) => node; + + public virtual Node Visit(AnonymousFunction node) => node; + + public virtual Node Visit(VarArg node) => node; + + public virtual Node Visit(ExpressionStatement node) => node; + + public virtual Node Visit(While node) => node; + + public virtual Node Visit(LocalDeclare node) => node; + + public virtual Node Visit(Assign node) => node; + + public virtual Node Visit(GenericFor node) => node; + + public virtual Node Visit(NumericFor node) => node; + + public virtual Node Visit(If node) => node; + + public virtual Node Visit(If.Clause node) => node; + + public virtual Node Visit(LocalFunction node) => node; + + public virtual Node Visit(Function node) => node; + + public virtual Node Visit(Break node) => node; + + public virtual Node Visit(Do node) => node; + + public virtual Node Visit(Repeat node) => node; + + public virtual Node Visit(Return node) => node; + + public virtual Node Visit(ParameterList node) => node; + + public virtual Node Visit(StringLiteral node) => node; + + public virtual Node Visit(NumberLiteral node) => node; + + public virtual Node Visit(BooleanLiteral node) => node; + + public virtual Node Visit(Nil node) => node; + + public virtual Node Visit(Block node) => node; + + public virtual Node Visit(Goto node) => node; + + public virtual Node Visit(Label node) => node; + + public Node Visit(Node node) => node.Accept(this); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/AstWalker.cs b/bot/src/Syntax/Ast/Visitors/AstWalker.cs new file mode 100644 index 0000000..5ff8c28 --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/AstWalker.cs @@ -0,0 +1,228 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax.Semantic; + +namespace MoonsecDeobfuscator.Ast; + +public abstract class AstWalker +{ + public SymbolTable? SymbolTable; + + public void Walk(Node node, bool symbols = false) + { + if (symbols) + SymbolTable = SymbolTableBuilder.Build(node); + + Visit(node); + } + + protected VariableInfo? GetVariable(string name) => SymbolTable?.GetVariable(name); + + protected virtual void VisitList(NodeList list) where TNode : Node + { + foreach (var node in list) + Visit(node); + } + + public virtual void Visit(Name node) + { + } + + public virtual void Visit(ElementAccess node) + { + Visit(node.Table); + Visit(node.Key); + } + + public virtual void Visit(MemberAccess node) + { + Visit(node.Table); + Visit(node.Key); + } + + public virtual void Visit(BinaryExpression node) + { + Visit(node.Left); + Visit(node.Right); + } + + public virtual void Visit(UnaryExpression node) + { + Visit(node.Operand); + } + + public virtual void Visit(Call node) + { + Visit(node.Function); + VisitList(node.Arguments); + } + + public virtual void Visit(MethodCall node) + { + Visit(node.Function); + Visit(node.MethodName); + VisitList(node.Arguments); + } + + public virtual void Visit(Table node) + { + VisitList(node.Entries); + } + + public virtual void Visit(Table.Entry node) + { + var key = node.Key; + + if (key != null) + Visit(key); + + Visit(node.Value); + } + + public virtual void Visit(AnonymousFunction node) + { + Visit(node.Parameters); + Visit(node.Body); + } + + public virtual void Visit(VarArg node) + { + } + + public virtual void Visit(ExpressionStatement node) + { + Visit(node.Expression); + } + + public virtual void Visit(While node) + { + Visit(node.Condition); + Visit(node.Body); + } + + public virtual void Visit(LocalDeclare node) + { + VisitList(node.Names); + VisitList(node.Values); + } + + public virtual void Visit(Assign node) + { + VisitList(node.Variables); + VisitList(node.Values); + } + + public virtual void Visit(GenericFor node) + { + VisitList(node.Names); + VisitList(node.Expressions); + Visit(node.Body); + } + + public virtual void Visit(NumericFor node) + { + Visit(node.IteratorName); + Visit(node.InitialValue); + Visit(node.FinalValue); + + var step = node.Step; + + if (step != null) + Visit(step); + + Visit(node.Body); + } + + public virtual void Visit(If node) + { + Visit(node.IfClause); + VisitList(node.ElseIfClauses); + + var elseBody = node.ElseBody; + + if (elseBody != null) + Visit(elseBody); + } + + public virtual void Visit(If.Clause node) + { + Visit(node.Condition); + Visit(node.Body); + } + + public virtual void Visit(LocalFunction node) + { + Visit(node.Name); + Visit(node.Parameters); + Visit(node.Body); + } + + public virtual void Visit(Function node) + { + Visit(node.Name); + Visit(node.Parameters); + Visit(node.Body); + } + + public virtual void Visit(Break node) + { + } + + public virtual void Visit(Do node) + { + Visit(node.Body); + } + + public virtual void Visit(Repeat node) + { + Visit(node.Body); + Visit(node.Condition); + } + + public virtual void Visit(Return node) + { + VisitList(node.Values); + } + + public virtual void Visit(ParameterList node) + { + VisitList(node.Names); + } + + public virtual void Visit(StringLiteral node) + { + } + + public virtual void Visit(NumberLiteral node) + { + } + + public virtual void Visit(BooleanLiteral node) + { + } + + public virtual void Visit(Nil node) + { + } + + public virtual void Visit(Block node) + { + VisitList(node.Statements); + } + + public virtual void Visit(Goto node) + { + Visit(node.Name); + } + + public virtual void Visit(Label node) + { + Visit(node.Name); + } + + public void Visit(Node node) + { + node.Accept(this); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/IRewriteDispatch.cs b/bot/src/Syntax/Ast/Visitors/IRewriteDispatch.cs new file mode 100644 index 0000000..1d77f19 --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/IRewriteDispatch.cs @@ -0,0 +1,6 @@ +namespace MoonsecDeobfuscator.Ast; + +public interface IRewriteDispatch +{ + void Rewrite(Node node, bool symbols, bool fixedPoint); +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/Order.cs b/bot/src/Syntax/Ast/Visitors/Order.cs new file mode 100644 index 0000000..9f7deec --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/Order.cs @@ -0,0 +1,7 @@ +namespace MoonsecDeobfuscator.Ast; + +public enum Order +{ + PreOrder, + PostOrder +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/PostOrderRewriteDispatch.cs b/bot/src/Syntax/Ast/Visitors/PostOrderRewriteDispatch.cs new file mode 100644 index 0000000..005d190 --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/PostOrderRewriteDispatch.cs @@ -0,0 +1,460 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax.Semantic; + +namespace MoonsecDeobfuscator.Ast; + +// children -> self +public class PostOrderRewriteDispatch(AstRewriter rewriter) : AstRewriter, IRewriteDispatch +{ + private bool _changed; + + public void Rewrite(Node node, bool symbols, bool fixedPoint) + { + do + { + if (symbols) + rewriter.SymbolTable = SymbolTableBuilder.Build(node); + + _changed = false; + node.Accept(this); + } + while (_changed && fixedPoint); + } + + private void VisitList(NodeList list) where TNode : Node + { + for (var i = 0; i < list.Count; i++) + { + var oldNode = list[i]; + var newNode = Visit(oldNode); + + if (oldNode != newNode) + { + _changed = true; + list[i] = (TNode) newNode; + } + } + } + + public override Node Visit(Name node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(ElementAccess node) + { + node.Table = (Expression) Visit(node.Table); + node.Key = (Expression) Visit(node.Key); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(MemberAccess node) + { + node.Table = (Expression) Visit(node.Table); + node.Key = (Name) Visit(node.Key); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(BinaryExpression node) + { + node.Left = (Expression) Visit(node.Left); + node.Right = (Expression) Visit(node.Right); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(UnaryExpression node) + { + node.Operand = (Expression) Visit(node.Operand); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Call node) + { + node.Function = (Expression) Visit(node.Function); + VisitList(node.Arguments); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(MethodCall node) + { + node.Function = (Expression) Visit(node.Function); + node.MethodName = (Name) Visit(node.MethodName); + VisitList(node.Arguments); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Table node) + { + VisitList(node.Entries); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Table.Entry node) + { + var key = node.Key; + + if (key != null) + node.Key = (Expression) Visit(key); + + node.Value = (Expression) Visit(node.Value); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(AnonymousFunction node) + { + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(VarArg node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(ExpressionStatement node) + { + node.Expression = (Expression) Visit(node.Expression); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(While node) + { + node.Condition = (Expression) Visit(node.Condition); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(LocalDeclare node) + { + VisitList(node.Names); + VisitList(node.Values); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Assign node) + { + VisitList(node.Variables); + VisitList(node.Values); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(GenericFor node) + { + VisitList(node.Names); + VisitList(node.Expressions); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(NumericFor node) + { + node.IteratorName = (Name) Visit(node.IteratorName); + node.InitialValue = (Expression) Visit(node.InitialValue); + node.FinalValue = (Expression) Visit(node.FinalValue); + + var step = node.Step; + + if (step != null) + node.Step = (Expression) Visit(step); + + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(If node) + { + node.IfClause = (If.Clause) Visit(node.IfClause); + VisitList(node.ElseIfClauses); + + var elseBody = node.ElseBody; + + if (elseBody != null) + node.ElseBody = (Block) Visit(elseBody); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(If.Clause node) + { + node.Condition = (Expression) Visit(node.Condition); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(LocalFunction node) + { + node.Name = (Name) Visit(node.Name); + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Function node) + { + node.Name = (Name) Visit(node.Name); + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Break node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Do node) + { + node.Body = (Block) Visit(node.Body); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Repeat node) + { + node.Body = (Block) Visit(node.Body); + node.Condition = (Expression) Visit(node.Condition); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Return node) + { + VisitList(node.Values); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(ParameterList node) + { + VisitList(node.Names); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(StringLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(NumberLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(BooleanLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Nil node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Block node) + { + VisitList(node.Statements); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Goto node) + { + node.Name = (Name) Visit(node.Name); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } + + public override Node Visit(Label node) + { + node.Name = (Name) Visit(node.Name); + + var newNode = rewriter.Visit(node); + + if (newNode != node) + _changed = true; + + return newNode; + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Ast/Visitors/PreOrderRewriteDispatch.cs b/bot/src/Syntax/Ast/Visitors/PreOrderRewriteDispatch.cs new file mode 100644 index 0000000..063e74a --- /dev/null +++ b/bot/src/Syntax/Ast/Visitors/PreOrderRewriteDispatch.cs @@ -0,0 +1,559 @@ +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax.Semantic; + +namespace MoonsecDeobfuscator.Ast; + +// self -> children +public class PreOrderRewriteDispatch(AstRewriter rewriter) : AstRewriter, IRewriteDispatch +{ + private bool _changed; + + public void Rewrite(Node node, bool symbols, bool fixedPoint) + { + do + { + if (symbols) + rewriter.SymbolTable = SymbolTableBuilder.Build(node); + + _changed = false; + node.Accept(this); + } + while (_changed && fixedPoint); + } + + private void VisitList(NodeList list) where TNode : Node + { + for (var i = 0; i < list.Count; i++) + { + var oldNode = list[i]; + var newNode = Visit(oldNode); + + if (oldNode != newNode) + { + _changed = true; + list[i] = (TNode) newNode; + } + } + } + + public override Node Visit(Name node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(ElementAccess node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Table = (Expression) Visit(node.Table); + node.Key = (Expression) Visit(node.Key); + + return node; + } + + public override Node Visit(MemberAccess node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Table = (Expression) Visit(node.Table); + node.Key = (Name) Visit(node.Key); + + return node; + } + + public override Node Visit(BinaryExpression node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Left = (Expression) Visit(node.Left); + node.Right = (Expression) Visit(node.Right); + + return node; + } + + public override Node Visit(UnaryExpression node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Operand = (Expression) Visit(node.Operand); + + return node; + } + + public override Node Visit(Call node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Function = (Expression) Visit(node.Function); + VisitList(node.Arguments); + + return node; + } + + public override Node Visit(MethodCall node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Function = (Expression) Visit(node.Function); + node.MethodName = (Name) Visit(node.MethodName); + VisitList(node.Arguments); + + return node; + } + + public override Node Visit(Table node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Entries); + + return node; + } + + public override Node Visit(Table.Entry node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + var key = node.Key; + + if (key != null) + node.Key = (Expression) Visit(key); + + node.Value = (Expression) Visit(node.Value); + + return node; + } + + public override Node Visit(AnonymousFunction node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(VarArg node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(ExpressionStatement node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Expression = (Expression) Visit(node.Expression); + + return node; + } + + public override Node Visit(While node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Condition = (Expression) Visit(node.Condition); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(LocalDeclare node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Names); + VisitList(node.Values); + + return node; + } + + public override Node Visit(Assign node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Variables); + VisitList(node.Values); + + return node; + } + + public override Node Visit(GenericFor node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Names); + VisitList(node.Expressions); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(NumericFor node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.IteratorName = (Name) Visit(node.IteratorName); + node.InitialValue = (Expression) Visit(node.InitialValue); + node.FinalValue = (Expression) Visit(node.FinalValue); + + var step = node.Step; + + if (step != null) + node.Step = (Expression) Visit(step); + + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(If node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.IfClause = (If.Clause) Visit(node.IfClause); + VisitList(node.ElseIfClauses); + + var elseBody = node.ElseBody; + + if (elseBody != null) + node.ElseBody = (Block) Visit(elseBody); + + return node; + } + + public override Node Visit(If.Clause node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Condition = (Expression) Visit(node.Condition); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(LocalFunction node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Name = (Name) Visit(node.Name); + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(Function node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Name = (Name) Visit(node.Name); + node.Parameters = (ParameterList) Visit(node.Parameters); + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(Break node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(Do node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Body = (Block) Visit(node.Body); + + return node; + } + + public override Node Visit(Repeat node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Body = (Block) Visit(node.Body); + node.Condition = (Expression) Visit(node.Condition); + + return node; + } + + public override Node Visit(Return node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Values); + + return node; + } + + public override Node Visit(ParameterList node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Names); + + return node; + } + + public override Node Visit(StringLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(NumberLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(BooleanLiteral node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(Nil node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + return node; + } + + public override Node Visit(Block node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + VisitList(node.Statements); + + return node; + } + + public override Node Visit(Goto node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Name = (Name) Visit(node.Name); + + return node; + } + + public override Node Visit(Label node) + { + var newNode = rewriter.Visit(node); + + if (newNode != node) + { + _changed = true; + return newNode; + } + + node.Name = (Name) Visit(node.Name); + + return node; + } +} \ No newline at end of file diff --git a/bot/src/Syntax/CstToAstVisitor.cs b/bot/src/Syntax/CstToAstVisitor.cs new file mode 100644 index 0000000..196f15a --- /dev/null +++ b/bot/src/Syntax/CstToAstVisitor.cs @@ -0,0 +1,338 @@ +using System.Globalization; +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Literals; +using MoonsecDeobfuscator.Ast.Statements; +using MoonsecDeobfuscator.Syntax.Parser; + +namespace MoonsecDeobfuscator.Syntax; + +public class CstToAstVisitor : LuaBaseVisitor +{ + public override Block VisitBlock(LuaParser.BlockContext ctx) + { + var statContext = ctx.stat().Where(stat => stat is not LuaParser.StatSemiContext).ToList(); + var stats = new NodeList(statContext.Count); + + foreach (var stat in statContext) + { + var node = Visit(stat); + + if (node is Expression expression) + node = new ExpressionStatement(expression); + + stats.Add((Statement) node); + } + + if (ctx.retstat() != null) + stats.Add(VisitRetstat(ctx.retstat())); + + return new Block(stats); + } + + public override Assign VisitStatAssign(LuaParser.StatAssignContext ctx) => + new(GetVarList(ctx.varlist()), GetExpList(ctx.explist())); + + public override Call VisitStatCall(LuaParser.StatCallContext ctx) => VisitFunctioncall(ctx.functioncall()); + + public override Break VisitStatBreak(LuaParser.StatBreakContext ctx) => new(); + + public override Do VisitStatDo(LuaParser.StatDoContext ctx) => new(VisitBlock(ctx.block())); + + public override While VisitStatWhile(LuaParser.StatWhileContext ctx) => + new((Expression) Visit(ctx.exp()), VisitBlock(ctx.block())); + + public override Repeat VisitStatRepeat(LuaParser.StatRepeatContext ctx) => + new(VisitBlock(ctx.block()), (Expression) Visit(ctx.exp())); + + public override If VisitStatIf(LuaParser.StatIfContext ctx) + { + var ifCtx = ctx.ifstmt(); + var elseIfCtx = ctx.elseifstmt(); + var elseCtx = ctx.elsestmt(); + + var ifClause = new If.Clause((Expression) Visit(ifCtx.exp()), VisitBlock(ifCtx.block())); + var elseIfClause = elseIfCtx.exp() + .Zip(elseIfCtx.block()) + .Select(it => new If.Clause((Expression) Visit(it.First), VisitBlock(it.Second))); + var elseBody = elseCtx.block() != null + ? VisitBlock(elseCtx.block()) + : null; + + return new If(ifClause, new NodeList(elseIfClause), elseBody); + } + + public override NumericFor VisitStatNumericFor(LuaParser.StatNumericForContext ctx) + { + var expCtx = ctx.exp(); + + return new NumericFor( + new Name(ctx.NAME().GetText()), + (Expression) Visit(expCtx[0]), + (Expression) Visit(expCtx[1]), + expCtx.Length > 2 ? (Expression) Visit(expCtx[2]) : null, + VisitBlock(ctx.block()) + ); + } + + public override GenericFor VisitStatGenericFor(LuaParser.StatGenericForContext ctx) => + new(GetNameList(ctx.namelist()), GetExpList(ctx.explist()), VisitBlock(ctx.block())); + + public override Function VisitStatFunction(LuaParser.StatFunctionContext ctx) + { + var funcBodyCtx = ctx.funcbody(); + + return new Function( + new Name(ctx.funcname().GetText()), + GetParList(funcBodyCtx.parlist()), + VisitBlock(funcBodyCtx.block()) + ); + } + + public override LocalFunction VisitStatLocalFunction(LuaParser.StatLocalFunctionContext ctx) + { + var funcBodyCtx = ctx.funcbody(); + + return new LocalFunction( + new Name(ctx.NAME().GetText()), + GetParList(funcBodyCtx.parlist()), + VisitBlock(funcBodyCtx.block()) + ); + } + + public override LocalDeclare VisitStatLocalDeclare(LuaParser.StatLocalDeclareContext ctx) => + new(GetNameList(ctx.namelist()), GetExpList(ctx.explist())); + + public override Goto VisitStatGoto(LuaParser.StatGotoContext ctx) => new(new Name(ctx.NAME().GetText())); + + public override Label VisitStatLabel(LuaParser.StatLabelContext ctx) => new(new Name(ctx.label().NAME().GetText())); + + public override Return VisitRetstat(LuaParser.RetstatContext ctx) => new(GetExpList(ctx.explist())); + + public override Nil VisitExpNil(LuaParser.ExpNilContext ctx) => new(); + + public override BooleanLiteral VisitExpFalse(LuaParser.ExpFalseContext ctx) => new(false); + + public override BooleanLiteral VisitExpTrue(LuaParser.ExpTrueContext ctx) => new(true); + + public override NumberLiteral VisitExpNumber(LuaParser.ExpNumberContext ctx) + { + var numberCtx = ctx.number(); + + if (numberCtx.INT() != null || numberCtx.FLOAT() != null) + return new NumberLiteral(double.Parse(numberCtx.GetText())); + + return new NumberLiteral(int.Parse(numberCtx.GetText().Replace("0x", ""), NumberStyles.HexNumber)); + } + + public override StringLiteral VisitExpString(LuaParser.ExpStringContext ctx) => new(ctx.@string().GetText()); + + public override VarArg VisitExpVarArg(LuaParser.ExpVarArgContext ctx) => new(); + + public override AnonymousFunction VisitExpFunction(LuaParser.ExpFunctionContext ctx) + { + var funcBodyCtx = ctx.functiondef().funcbody(); + return new AnonymousFunction(GetParList(funcBodyCtx.parlist()), VisitBlock(funcBodyCtx.block())); + } + + public override Expression VisitPrefixexp(LuaParser.PrefixexpContext ctx) + { + var nameAndArgsCtx = ctx.nameAndArgs(); + var varOrExp = VisitVarOrExp(ctx.varOrExp()); + + return nameAndArgsCtx.Length == 0 ? varOrExp : GetCallChain(varOrExp, nameAndArgsCtx); + } + + public override Table VisitExpTable(LuaParser.ExpTableContext ctx) => GetTable(ctx.tableconstructor()); + + public override BinaryExpression VisitExpPow(LuaParser.ExpPowContext ctx) => + new(BinaryOperator.Pow, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + + public override UnaryExpression VisitExpUnary(LuaParser.ExpUnaryContext ctx) + { + var @operator = ctx.operatorUnary().GetText() switch + { + "not" => UnaryOperator.Not, + "#" => UnaryOperator.Length, + "-" => UnaryOperator.Negate, + _ => throw new Exception($"Invalid operator: {ctx.GetText()}") + }; + + return new UnaryExpression(@operator, (Expression) Visit(ctx.exp())); + } + + public override BinaryExpression VisitExpMulDivMod(LuaParser.ExpMulDivModContext ctx) + { + var @operator = ctx.operatorMulDivMod().GetText() switch + { + "*" => BinaryOperator.Mul, + "/" => BinaryOperator.Div, + "%" => BinaryOperator.Mod, + _ => throw new Exception($"Invalid operator: {ctx.GetText()}") + }; + + return new BinaryExpression(@operator, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + } + + public override BinaryExpression VisitExpAddSub(LuaParser.ExpAddSubContext ctx) + { + var @operator = ctx.operatorAddSub().GetText() == "+" ? BinaryOperator.Add : BinaryOperator.Sub; + return new BinaryExpression(@operator, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + } + + public override BinaryExpression VisitExpConcat(LuaParser.ExpConcatContext ctx) => + new(BinaryOperator.Concat, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + + public override BinaryExpression VisitExpCompare(LuaParser.ExpCompareContext ctx) + { + var @operator = ctx.operatorComparison().GetText() switch + { + "==" => BinaryOperator.Equals, + "~=" => BinaryOperator.NotEquals, + "<=" => BinaryOperator.LessThanOrEquals, + ">=" => BinaryOperator.GreaterThanOrEquals, + "<" => BinaryOperator.LessThan, + ">" => BinaryOperator.GreaterThan, + _ => throw new Exception($"Invalid operator: {ctx.GetText()}") + }; + + return new BinaryExpression(@operator, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + } + + public override BinaryExpression VisitExpAnd(LuaParser.ExpAndContext ctx) => + new(BinaryOperator.And, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + + public override BinaryExpression VisitExpOr(LuaParser.ExpOrContext ctx) => + new(BinaryOperator.Or, (Expression) Visit(ctx.exp(0)), (Expression) Visit(ctx.exp(1))); + + public override Call VisitFunctioncall(LuaParser.FunctioncallContext ctx) => + GetCallChain(VisitVarOrExp(ctx.varOrExp()), ctx.nameAndArgs()); + + public override Expression VisitVarOrExp(LuaParser.VarOrExpContext ctx) => + ctx.exp() != null ? (Expression) Visit(ctx.exp()) : VisitVar(ctx.var()); + + public override Variable VisitVar(LuaParser.VarContext ctx) + { + var varSuffixCtx = ctx.varSuffix(); + var name = ctx.NAME() != null ? new Name(ctx.NAME().GetText()) : (Expression) Visit(ctx.exp()); + + if (varSuffixCtx.Length == 0) + return (Variable) name; + + return (Variable) varSuffixCtx.Aggregate(name, (expression, suffix) => suffix.NAME() != null + ? new MemberAccess(expression, new Name(suffix.NAME().GetText())) + : new ElementAccess(expression, (Expression) Visit(suffix.exp())) + ); + } + + private NodeList GetExpList(LuaParser.ExplistContext? ctx) + { + if (ctx == null) + return []; + + var exprs = ctx.exp(); + var list = new NodeList(exprs.Length); + + foreach (var expression in exprs) + list.Add((Expression) Visit(expression)); + + return list; + } + + private static NodeList GetNameList(LuaParser.NamelistContext context) + { + var names = context.NAME(); + var list = new NodeList(names.Length); + + foreach (var name in names) + list.Add(new Name(name.GetText())); + + return list; + } + + private NodeList GetVarList(LuaParser.VarlistContext context) + { + var vars = context.var(); + var list = new NodeList(vars.Length); + + foreach (var variable in vars) + list.Add(VisitVar(variable)); + + return list; + } + + private NodeList GetArgs(LuaParser.ArgsContext ctx) + { + if (ctx.explist() != null) + return GetExpList(ctx.explist()); + + var args = new NodeList(); + + if (ctx.tableconstructor() != null) + args.Add(GetTable(ctx.tableconstructor())); + else if (ctx.@string() != null) + args.Add(new StringLiteral(ctx.@string().GetText())); + + return args; + } + + private Call GetCallChain(Expression varOrExp, LuaParser.NameAndArgsContext[] nameAndArgsCtx) + { + return (Call) nameAndArgsCtx.Aggregate(varOrExp, (expression, nameAndArgs) => + { + var args = GetArgs(nameAndArgs.args()); + + return nameAndArgs.NAME() != null + ? new MethodCall(expression, new Name(nameAndArgs.NAME().GetText()), args) + : new Call(expression, args); + }); + } + + private Table.Entry GetField(LuaParser.FieldContext ctx) + { + var expCtx = ctx.exp(); + + if (expCtx.Length == 2) + { + var key = (Expression) Visit(expCtx[0]); + var value = (Expression) Visit(expCtx[1]); + + return new Table.Entry(key, value); + } + + if (ctx.NAME() != null) + { + var key = new Name(ctx.NAME().GetText()); + var value = (Expression) Visit(expCtx[0]); + + return new Table.Entry(key, value); + } + + return new Table.Entry((Expression) Visit(expCtx[0])); + } + + private Table GetTable(LuaParser.TableconstructorContext ctx) + { + var entries = new NodeList(); + var fieldListCtx = ctx.fieldlist(); + + if (fieldListCtx != null) + { + foreach (var fieldCtx in fieldListCtx.field()) + entries.Add(GetField(fieldCtx)); + } + + return new Table(entries); + } + + private static ParameterList GetParList(LuaParser.ParlistContext? ctx) + { + if (ctx == null) + return new ParameterList(); + + var names = ctx.namelist() != null ? GetNameList(ctx.namelist()) : []; + var isVarArg = ctx.children.Any(child => child.GetText() == "..."); + + return new ParameterList(names, isVarArg); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Grammar/Lua.g4 b/bot/src/Syntax/Grammar/Lua.g4 new file mode 100644 index 0000000..f866676 --- /dev/null +++ b/bot/src/Syntax/Grammar/Lua.g4 @@ -0,0 +1,359 @@ +/* +BSD License + +Copyright (c) 2013, Kazunori Sakamoto +Copyright (c) 2016, Alexander Alexeev +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the NAME of Rainer Schuster nor the NAMEs of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This grammar file derived from: + + Lua 5.3 Reference Manual + http://www.lua.org/manual/5.3/manual.html + + Lua 5.2 Reference Manual + http://www.lua.org/manual/5.2/manual.html + + Lua 5.1 grammar written by Nicolai Mainiero + http://www.antlr3.org/grammar/1178608849736/Lua.g + +Tested by Kazunori Sakamoto with Test suite for Lua 5.2 (http://www.lua.org/tests/5.2/) + +Tested by Alexander Alexeev with Test suite for Lua 5.3 http://www.lua.org/tests/lua-5.3.2-tests.tar.gz +*/ + +grammar Lua; + +chunk + : block EOF + ; + +block + : stat* retstat? + ; + +stat + : ';' # statSemi + | varlist '=' explist # statAssign + | functioncall # statCall + | label # statLabel + | 'break' # statBreak + | 'goto' NAME # statGoto + | 'do' block 'end' # statDo + | 'while' exp 'do' block 'end' # statWhile + | 'repeat' block 'until' exp # statRepeat + | ifstmt elseifstmt elsestmt 'end' # statIf + | 'for' NAME '=' exp ',' exp (',' exp)? 'do' block 'end' # statNumericFor + | 'for' namelist 'in' explist 'do' block 'end' # statGenericFor + | 'function' funcname funcbody # statFunction + | 'local' 'function' NAME funcbody # statLocalFunction + | 'local' namelist ('=' explist)? # statLocalDeclare + ; + +ifstmt + : + 'if' exp 'then' block + ; + +elseifstmt + : + ('elseif' exp 'then' block)* + ; + +elsestmt + : + ('else' block)? + ; + +retstat + : 'return' explist? ';'? + ; + +label + : '::' NAME '::' + ; + +funcname + : NAME ('.' NAME)* (':' NAME)? + ; + +varlist + : var (',' var)* + ; + +namelist + : NAME (',' NAME)* + ; + +explist + : exp (',' exp)* + ; + +exp + : 'nil' # expNil + | 'false' # expFalse + | 'true' # expTrue + | number # expNumber + | string # expString + | '...' # expVarArg + | functiondef # expFunction + | prefixexp # expPrefix + | tableconstructor # expTable + | exp operatorPower exp # expPow + | operatorUnary exp # expUnary + | exp operatorMulDivMod exp # expMulDivMod + | exp operatorAddSub exp # expAddSub + | exp operatorStrcat exp # expConcat + | exp operatorComparison exp # expCompare + | exp operatorAnd exp # expAnd + | exp operatorOr exp # expOr + | exp operatorBitwise exp # expBitwise + ; + +prefixexp + : varOrExp nameAndArgs* + ; + +functioncall + : varOrExp nameAndArgs+ + ; + +varOrExp + : var | '(' exp ')' + ; + +var + : (NAME | '(' exp ')' varSuffix) varSuffix* + ; + +/* +varSuffix + : nameAndArgs* ('[' exp ']' | '.' NAME) + ; +*/ + +varSuffix + : '[' exp ']' + | '.' NAME + ; + +nameAndArgs + : (':' NAME)? args + ; + +/* +var + : NAME | prefixexp '[' exp ']' | prefixexp '.' NAME + ; + +prefixexp + : var | functioncall | '(' exp ')' + ; + +functioncall + : prefixexp args | prefixexp ':' NAME args + ; +*/ + +args + : '(' explist? ')' | tableconstructor | string + ; + +functiondef + : 'function' funcbody + ; + +funcbody + : '(' parlist? ')' block 'end' + ; + +parlist + : namelist (',' '...')? | '...' + ; + +tableconstructor + : '{' fieldlist? '}' + ; + +fieldlist + : field (fieldsep field)* fieldsep? + ; + +field + : '[' exp ']' '=' exp | NAME '=' exp | exp + ; + +fieldsep + : ',' | ';' + ; + +operatorOr + : 'or'; + +operatorAnd + : 'and'; + +operatorComparison + : '<' | '>' | '<=' | '>=' | '~=' | '=='; + +operatorStrcat + : '..'; + +operatorAddSub + : '+' | '-'; + +operatorMulDivMod + : '*' | '/' | '%' | '//'; + +operatorBitwise + : '&' | '|' | '~' | '<<' | '>>'; + +operatorUnary + : 'not' | '#' | '-' | '~'; + +operatorPower + : '^'; + +number + : INT | HEX | FLOAT | HEX_FLOAT + ; + +string + : NORMALSTRING | CHARSTRING | LONGSTRING + ; + +// LEXER + +NAME + : [a-zA-Z_][a-zA-Z_0-9]* + ; + +NORMALSTRING + : '"' ( EscapeSequence | ~('\\'|'"') )* '"' + ; + +CHARSTRING + : '\'' ( EscapeSequence | ~('\''|'\\') )* '\'' + ; + +LONGSTRING + : '[' NESTED_STR ']' + ; + +fragment +NESTED_STR + : '=' NESTED_STR '=' + | '[' .*? ']' + ; + +INT + : Digit+ + ; + +HEX + : '0' [xX] HexDigit+ + ; + +FLOAT + : Digit+ '.' Digit* ExponentPart? + | '.' Digit+ ExponentPart? + | Digit+ ExponentPart + ; + +HEX_FLOAT + : '0' [xX] HexDigit+ '.' HexDigit* HexExponentPart? + | '0' [xX] '.' HexDigit+ HexExponentPart? + | '0' [xX] HexDigit+ HexExponentPart + ; + +fragment +ExponentPart + : [eE] [+-]? Digit+ + ; + +fragment +HexExponentPart + : [pP] [+-]? Digit+ + ; + +fragment +EscapeSequence + : '\\' [abfnrtvz"'\\] + | '\\' '\r'? '\n' + | DecimalEscape + | HexEscape + | UtfEscape + ; + +fragment +DecimalEscape + : '\\' Digit + | '\\' Digit Digit + | '\\' [0-2] Digit Digit + ; + +fragment +HexEscape + : '\\' 'x' HexDigit HexDigit + ; + +fragment +UtfEscape + : '\\' 'u{' HexDigit+ '}' + ; + +fragment +Digit + : [0-9] + ; + +fragment +HexDigit + : [0-9a-fA-F] + ; + +COMMENT + : '--[' NESTED_STR ']' -> channel(HIDDEN) + ; + +LINE_COMMENT + : '--' + ( // -- + | '[' '='* // --[== + | '[' '='* ~('='|'['|'\r'|'\n') ~('\r'|'\n')* // --[==AA + | ~('['|'\r'|'\n') ~('\r'|'\n')* // --AAA + ) ('\r\n'|'\r'|'\n'|EOF) + -> channel(HIDDEN) + ; + +WS + : [ \t\u000C\r\n]+ -> skip + ; + +SHEBANG + : '#' '!' ~('\n'|'\r')* -> channel(HIDDEN) + ; \ No newline at end of file diff --git a/bot/src/Syntax/Parser/LuaBaseVisitor.cs b/bot/src/Syntax/Parser/LuaBaseVisitor.cs new file mode 100644 index 0000000..f505b67 --- /dev/null +++ b/bot/src/Syntax/Parser/LuaBaseVisitor.cs @@ -0,0 +1,748 @@ +// Unreachable code detected +#pragma warning disable 0162 +// The variable '...' is assigned but its value is never used +#pragma warning disable 0219 +// Missing XML comment for publicly visible type or member '...' +#pragma warning disable 1591 +// Ambiguous reference in cref attribute +#pragma warning disable 419 + +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; + +namespace MoonsecDeobfuscator.Syntax.Parser; + +/// +/// This class provides an empty implementation of , +/// which can be extended to create a visitor which only needs to handle a subset +/// of the available methods. +/// +/// The return type of the visit operation. +[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")] +[System.Diagnostics.DebuggerNonUserCode] +[System.CLSCompliant(false)] +public partial class LuaBaseVisitor : AbstractParseTreeVisitor, ILuaVisitor { + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitChunk([NotNull] LuaParser.ChunkContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitBlock([NotNull] LuaParser.BlockContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statSemi + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatSemi([NotNull] LuaParser.StatSemiContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the statAssign + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatAssign([NotNull] LuaParser.StatAssignContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statCall + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatCall([NotNull] LuaParser.StatCallContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statLabel + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatLabel([NotNull] LuaParser.StatLabelContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the statBreak + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatBreak([NotNull] LuaParser.StatBreakContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statGoto + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatGoto([NotNull] LuaParser.StatGotoContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the statDo + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatDo([NotNull] LuaParser.StatDoContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statWhile + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatWhile([NotNull] LuaParser.StatWhileContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statRepeat + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatRepeat([NotNull] LuaParser.StatRepeatContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statIf + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatIf([NotNull] LuaParser.StatIfContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statNumericFor + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatNumericFor([NotNull] LuaParser.StatNumericForContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statGenericFor + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatGenericFor([NotNull] LuaParser.StatGenericForContext ctx) { return VisitChildren(ctx); } + /// + /// Visit a parse tree produced by the statFunction + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatFunction([NotNull] LuaParser.StatFunctionContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the statLocalFunction + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatLocalFunction([NotNull] LuaParser.StatLocalFunctionContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the statLocalDeclare + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitStatLocalDeclare([NotNull] LuaParser.StatLocalDeclareContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitIfstmt([NotNull] LuaParser.IfstmtContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitElseifstmt([NotNull] LuaParser.ElseifstmtContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitElsestmt([NotNull] LuaParser.ElsestmtContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitRetstat([NotNull] LuaParser.RetstatContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitLabel([NotNull] LuaParser.LabelContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFuncname([NotNull] LuaParser.FuncnameContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitVarlist([NotNull] LuaParser.VarlistContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitNamelist([NotNull] LuaParser.NamelistContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExplist([NotNull] LuaParser.ExplistContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expNumber + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpNumber([NotNull] LuaParser.ExpNumberContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expTrue + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpTrue([NotNull] LuaParser.ExpTrueContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expOr + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpOr([NotNull] LuaParser.ExpOrContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expBitwise + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpBitwise([NotNull] LuaParser.ExpBitwiseContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expMulDivMod + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpMulDivMod([NotNull] LuaParser.ExpMulDivModContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expFalse + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpFalse([NotNull] LuaParser.ExpFalseContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expString + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpString([NotNull] LuaParser.ExpStringContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expPrefix + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpPrefix([NotNull] LuaParser.ExpPrefixContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expUnary + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpUnary([NotNull] LuaParser.ExpUnaryContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expAnd + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpAnd([NotNull] LuaParser.ExpAndContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expPow + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpPow([NotNull] LuaParser.ExpPowContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expFunction + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpFunction([NotNull] LuaParser.ExpFunctionContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expCompare + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpCompare([NotNull] LuaParser.ExpCompareContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expConcat + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpConcat([NotNull] LuaParser.ExpConcatContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expNil + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpNil([NotNull] LuaParser.ExpNilContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expAddSub + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpAddSub([NotNull] LuaParser.ExpAddSubContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expVarArg + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpVarArg([NotNull] LuaParser.ExpVarArgContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by the expTable + /// labeled alternative in . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitExpTable([NotNull] LuaParser.ExpTableContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitPrefixexp([NotNull] LuaParser.PrefixexpContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFunctioncall([NotNull] LuaParser.FunctioncallContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitVarOrExp([NotNull] LuaParser.VarOrExpContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitVar([NotNull] LuaParser.VarContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitVarSuffix([NotNull] LuaParser.VarSuffixContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitNameAndArgs([NotNull] LuaParser.NameAndArgsContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitArgs([NotNull] LuaParser.ArgsContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFunctiondef([NotNull] LuaParser.FunctiondefContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFuncbody([NotNull] LuaParser.FuncbodyContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitParlist([NotNull] LuaParser.ParlistContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitTableconstructor([NotNull] LuaParser.TableconstructorContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFieldlist([NotNull] LuaParser.FieldlistContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitField([NotNull] LuaParser.FieldContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitFieldsep([NotNull] LuaParser.FieldsepContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorOr([NotNull] LuaParser.OperatorOrContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorAnd([NotNull] LuaParser.OperatorAndContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorComparison([NotNull] LuaParser.OperatorComparisonContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorStrcat([NotNull] LuaParser.OperatorStrcatContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorAddSub([NotNull] LuaParser.OperatorAddSubContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorMulDivMod([NotNull] LuaParser.OperatorMulDivModContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorBitwise([NotNull] LuaParser.OperatorBitwiseContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorUnary([NotNull] LuaParser.OperatorUnaryContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitOperatorPower([NotNull] LuaParser.OperatorPowerContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitNumber([NotNull] LuaParser.NumberContext context) { return VisitChildren(context); } + /// + /// Visit a parse tree produced by . + /// + /// The default implementation returns the result of calling + /// on . + /// + /// + /// The parse tree. + /// The visitor result. + public virtual Result VisitString([NotNull] LuaParser.StringContext context) { return VisitChildren(context); } +} diff --git a/bot/src/Syntax/Parser/LuaLexer.cs b/bot/src/Syntax/Parser/LuaLexer.cs new file mode 100644 index 0000000..09706b9 --- /dev/null +++ b/bot/src/Syntax/Parser/LuaLexer.cs @@ -0,0 +1,323 @@ +// Unreachable code detected +#pragma warning disable 0162 +// The variable '...' is assigned but its value is never used +#pragma warning disable 0219 +// Missing XML comment for publicly visible type or member '...' +#pragma warning disable 1591 +// Ambiguous reference in cref attribute +#pragma warning disable 419 + +using Antlr4.Runtime; +using Antlr4.Runtime.Atn; +using Antlr4.Runtime.Misc; +using DFA = Antlr4.Runtime.Dfa.DFA; + +namespace MoonsecDeobfuscator.Syntax.Parser; + +[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")] +[System.CLSCompliant(false)] +public partial class LuaLexer : Lexer { + protected static DFA[] decisionToDFA; + protected static PredictionContextCache sharedContextCache = new PredictionContextCache(); + public const int + T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9, + T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17, + T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, T__23=24, + T__24=25, T__25=26, T__26=27, T__27=28, T__28=29, T__29=30, T__30=31, + T__31=32, T__32=33, T__33=34, T__34=35, T__35=36, T__36=37, T__37=38, + T__38=39, T__39=40, T__40=41, T__41=42, T__42=43, T__43=44, T__44=45, + T__45=46, T__46=47, T__47=48, T__48=49, T__49=50, T__50=51, T__51=52, + T__52=53, T__53=54, T__54=55, NAME=56, NORMALSTRING=57, CHARSTRING=58, + LONGSTRING=59, INT=60, HEX=61, FLOAT=62, HEX_FLOAT=63, COMMENT=64, LINE_COMMENT=65, + WS=66, SHEBANG=67; + public static string[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static string[] modeNames = { + "DEFAULT_MODE" + }; + + public static readonly string[] ruleNames = { + "T__0", "T__1", "T__2", "T__3", "T__4", "T__5", "T__6", "T__7", "T__8", + "T__9", "T__10", "T__11", "T__12", "T__13", "T__14", "T__15", "T__16", + "T__17", "T__18", "T__19", "T__20", "T__21", "T__22", "T__23", "T__24", + "T__25", "T__26", "T__27", "T__28", "T__29", "T__30", "T__31", "T__32", + "T__33", "T__34", "T__35", "T__36", "T__37", "T__38", "T__39", "T__40", + "T__41", "T__42", "T__43", "T__44", "T__45", "T__46", "T__47", "T__48", + "T__49", "T__50", "T__51", "T__52", "T__53", "T__54", "NAME", "NORMALSTRING", + "CHARSTRING", "LONGSTRING", "NESTED_STR", "INT", "HEX", "FLOAT", "HEX_FLOAT", + "ExponentPart", "HexExponentPart", "EscapeSequence", "DecimalEscape", + "HexEscape", "UtfEscape", "Digit", "HexDigit", "COMMENT", "LINE_COMMENT", + "WS", "SHEBANG" + }; + + + public LuaLexer(ICharStream input) + : this(input, Console.Out, Console.Error) { } + + public LuaLexer(ICharStream input, TextWriter output, TextWriter errorOutput) + : base(input, output, errorOutput) + { + Interpreter = new LexerATNSimulator(this, _ATN, decisionToDFA, sharedContextCache); + } + + private static readonly string[] _LiteralNames = { + null, "';'", "'='", "'break'", "'goto'", "'do'", "'end'", "'while'", "'repeat'", + "'until'", "'for'", "','", "'in'", "'function'", "'local'", "'if'", "'then'", + "'elseif'", "'else'", "'return'", "'::'", "'.'", "':'", "'nil'", "'false'", + "'true'", "'...'", "'('", "')'", "'['", "']'", "'{'", "'}'", "'or'", "'and'", + "'<'", "'>'", "'<='", "'>='", "'~='", "'=='", "'..'", "'+'", "'-'", "'*'", + "'/'", "'%'", "'//'", "'&'", "'|'", "'~'", "'<<'", "'>>'", "'not'", "'#'", + "'^'" + }; + private static readonly string[] _SymbolicNames = { + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "NAME", "NORMALSTRING", + "CHARSTRING", "LONGSTRING", "INT", "HEX", "FLOAT", "HEX_FLOAT", "COMMENT", + "LINE_COMMENT", "WS", "SHEBANG" + }; + public static readonly IVocabulary DefaultVocabulary = new Vocabulary(_LiteralNames, _SymbolicNames); + + [NotNull] + public override IVocabulary Vocabulary + { + get + { + return DefaultVocabulary; + } + } + + public override string GrammarFileName { get { return "Lua.g4"; } } + + public override string[] RuleNames { get { return ruleNames; } } + + public override string[] ChannelNames { get { return channelNames; } } + + public override string[] ModeNames { get { return modeNames; } } + + public override int[] SerializedAtn { get { return _serializedATN; } } + + static LuaLexer() { + decisionToDFA = new DFA[_ATN.NumberOfDecisions]; + for (int i = 0; i < _ATN.NumberOfDecisions; i++) { + decisionToDFA[i] = new DFA(_ATN.GetDecisionState(i), i); + } + } + private static int[] _serializedATN = { + 4,0,67,601,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, + 6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14, + 7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21, + 7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7,26,2,27,7,27,2,28, + 7,28,2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,32,2,33,7,33,2,34,7,34,2,35, + 7,35,2,36,7,36,2,37,7,37,2,38,7,38,2,39,7,39,2,40,7,40,2,41,7,41,2,42, + 7,42,2,43,7,43,2,44,7,44,2,45,7,45,2,46,7,46,2,47,7,47,2,48,7,48,2,49, + 7,49,2,50,7,50,2,51,7,51,2,52,7,52,2,53,7,53,2,54,7,54,2,55,7,55,2,56, + 7,56,2,57,7,57,2,58,7,58,2,59,7,59,2,60,7,60,2,61,7,61,2,62,7,62,2,63, + 7,63,2,64,7,64,2,65,7,65,2,66,7,66,2,67,7,67,2,68,7,68,2,69,7,69,2,70, + 7,70,2,71,7,71,2,72,7,72,2,73,7,73,2,74,7,74,2,75,7,75,1,0,1,0,1,1,1,1, + 1,2,1,2,1,2,1,2,1,2,1,2,1,3,1,3,1,3,1,3,1,3,1,4,1,4,1,4,1,5,1,5,1,5,1, + 5,1,6,1,6,1,6,1,6,1,6,1,6,1,7,1,7,1,7,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8, + 1,8,1,8,1,9,1,9,1,9,1,9,1,10,1,10,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1, + 12,1,12,1,12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1, + 15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1, + 17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,18,1,18,1,19,1,19,1,19,1,20,1, + 20,1,21,1,21,1,22,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1,23,1,23,1,24,1, + 24,1,24,1,24,1,24,1,25,1,25,1,25,1,25,1,26,1,26,1,27,1,27,1,28,1,28,1, + 29,1,29,1,30,1,30,1,31,1,31,1,32,1,32,1,32,1,33,1,33,1,33,1,33,1,34,1, + 34,1,35,1,35,1,36,1,36,1,36,1,37,1,37,1,37,1,38,1,38,1,38,1,39,1,39,1, + 39,1,40,1,40,1,40,1,41,1,41,1,42,1,42,1,43,1,43,1,44,1,44,1,45,1,45,1, + 46,1,46,1,46,1,47,1,47,1,48,1,48,1,49,1,49,1,50,1,50,1,50,1,51,1,51,1, + 51,1,52,1,52,1,52,1,52,1,53,1,53,1,54,1,54,1,55,1,55,5,55,345,8,55,10, + 55,12,55,348,9,55,1,56,1,56,1,56,5,56,353,8,56,10,56,12,56,356,9,56,1, + 56,1,56,1,57,1,57,1,57,5,57,363,8,57,10,57,12,57,366,9,57,1,57,1,57,1, + 58,1,58,1,58,1,58,1,59,1,59,1,59,1,59,1,59,1,59,5,59,380,8,59,10,59,12, + 59,383,9,59,1,59,3,59,386,8,59,1,60,4,60,389,8,60,11,60,12,60,390,1,61, + 1,61,1,61,4,61,396,8,61,11,61,12,61,397,1,62,4,62,401,8,62,11,62,12,62, + 402,1,62,1,62,5,62,407,8,62,10,62,12,62,410,9,62,1,62,3,62,413,8,62,1, + 62,1,62,4,62,417,8,62,11,62,12,62,418,1,62,3,62,422,8,62,1,62,4,62,425, + 8,62,11,62,12,62,426,1,62,1,62,3,62,431,8,62,1,63,1,63,1,63,4,63,436,8, + 63,11,63,12,63,437,1,63,1,63,5,63,442,8,63,10,63,12,63,445,9,63,1,63,3, + 63,448,8,63,1,63,1,63,1,63,1,63,4,63,454,8,63,11,63,12,63,455,1,63,3,63, + 459,8,63,1,63,1,63,1,63,4,63,464,8,63,11,63,12,63,465,1,63,1,63,3,63,470, + 8,63,1,64,1,64,3,64,474,8,64,1,64,4,64,477,8,64,11,64,12,64,478,1,65,1, + 65,3,65,483,8,65,1,65,4,65,486,8,65,11,65,12,65,487,1,66,1,66,1,66,1,66, + 3,66,494,8,66,1,66,1,66,1,66,1,66,3,66,500,8,66,1,67,1,67,1,67,1,67,1, + 67,1,67,1,67,1,67,1,67,1,67,1,67,3,67,513,8,67,1,68,1,68,1,68,1,68,1,68, + 1,69,1,69,1,69,1,69,1,69,4,69,525,8,69,11,69,12,69,526,1,69,1,69,1,70, + 1,70,1,71,1,71,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,72,1,73,1,73, + 1,73,1,73,1,73,1,73,5,73,550,8,73,10,73,12,73,553,9,73,1,73,1,73,5,73, + 557,8,73,10,73,12,73,560,9,73,1,73,1,73,5,73,564,8,73,10,73,12,73,567, + 9,73,1,73,1,73,5,73,571,8,73,10,73,12,73,574,9,73,3,73,576,8,73,1,73,1, + 73,1,73,3,73,581,8,73,1,73,1,73,1,74,4,74,586,8,74,11,74,12,74,587,1,74, + 1,74,1,75,1,75,1,75,5,75,595,8,75,10,75,12,75,598,9,75,1,75,1,75,1,381, + 0,76,1,1,3,2,5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27, + 14,29,15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,49,25,51, + 26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,71,36,73,37,75, + 38,77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46,93,47,95,48,97,49,99, + 50,101,51,103,52,105,53,107,54,109,55,111,56,113,57,115,58,117,59,119, + 0,121,60,123,61,125,62,127,63,129,0,131,0,133,0,135,0,137,0,139,0,141, + 0,143,0,145,64,147,65,149,66,151,67,1,0,17,3,0,65,90,95,95,97,122,4,0, + 48,57,65,90,95,95,97,122,2,0,34,34,92,92,2,0,39,39,92,92,2,0,88,88,120, + 120,2,0,69,69,101,101,2,0,43,43,45,45,2,0,80,80,112,112,10,0,34,34,39, + 39,92,92,97,98,102,102,110,110,114,114,116,116,118,118,122,122,1,0,48, + 50,1,0,48,57,3,0,48,57,65,70,97,102,4,0,10,10,13,13,61,61,91,91,2,0,10, + 10,13,13,3,0,10,10,13,13,91,91,2,1,10,10,13,13,3,0,9,10,12,13,32,32,638, + 0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0, + 0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,23, + 1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,33,1,0,0, + 0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,43,1,0,0,0,0,45, + 1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,53,1,0,0,0,0,55,1,0,0, + 0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67, + 1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0, + 0,0,79,1,0,0,0,0,81,1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89, + 1,0,0,0,0,91,1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0, + 0,0,101,1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0, + 0,0,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,121,1,0,0, + 0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,145,1,0,0,0,0,147,1,0,0, + 0,0,149,1,0,0,0,0,151,1,0,0,0,1,153,1,0,0,0,3,155,1,0,0,0,5,157,1,0,0, + 0,7,163,1,0,0,0,9,168,1,0,0,0,11,171,1,0,0,0,13,175,1,0,0,0,15,181,1,0, + 0,0,17,188,1,0,0,0,19,194,1,0,0,0,21,198,1,0,0,0,23,200,1,0,0,0,25,203, + 1,0,0,0,27,212,1,0,0,0,29,218,1,0,0,0,31,221,1,0,0,0,33,226,1,0,0,0,35, + 233,1,0,0,0,37,238,1,0,0,0,39,245,1,0,0,0,41,248,1,0,0,0,43,250,1,0,0, + 0,45,252,1,0,0,0,47,256,1,0,0,0,49,262,1,0,0,0,51,267,1,0,0,0,53,271,1, + 0,0,0,55,273,1,0,0,0,57,275,1,0,0,0,59,277,1,0,0,0,61,279,1,0,0,0,63,281, + 1,0,0,0,65,283,1,0,0,0,67,286,1,0,0,0,69,290,1,0,0,0,71,292,1,0,0,0,73, + 294,1,0,0,0,75,297,1,0,0,0,77,300,1,0,0,0,79,303,1,0,0,0,81,306,1,0,0, + 0,83,309,1,0,0,0,85,311,1,0,0,0,87,313,1,0,0,0,89,315,1,0,0,0,91,317,1, + 0,0,0,93,319,1,0,0,0,95,322,1,0,0,0,97,324,1,0,0,0,99,326,1,0,0,0,101, + 328,1,0,0,0,103,331,1,0,0,0,105,334,1,0,0,0,107,338,1,0,0,0,109,340,1, + 0,0,0,111,342,1,0,0,0,113,349,1,0,0,0,115,359,1,0,0,0,117,369,1,0,0,0, + 119,385,1,0,0,0,121,388,1,0,0,0,123,392,1,0,0,0,125,430,1,0,0,0,127,469, + 1,0,0,0,129,471,1,0,0,0,131,480,1,0,0,0,133,499,1,0,0,0,135,512,1,0,0, + 0,137,514,1,0,0,0,139,519,1,0,0,0,141,530,1,0,0,0,143,532,1,0,0,0,145, + 534,1,0,0,0,147,543,1,0,0,0,149,585,1,0,0,0,151,591,1,0,0,0,153,154,5, + 59,0,0,154,2,1,0,0,0,155,156,5,61,0,0,156,4,1,0,0,0,157,158,5,98,0,0,158, + 159,5,114,0,0,159,160,5,101,0,0,160,161,5,97,0,0,161,162,5,107,0,0,162, + 6,1,0,0,0,163,164,5,103,0,0,164,165,5,111,0,0,165,166,5,116,0,0,166,167, + 5,111,0,0,167,8,1,0,0,0,168,169,5,100,0,0,169,170,5,111,0,0,170,10,1,0, + 0,0,171,172,5,101,0,0,172,173,5,110,0,0,173,174,5,100,0,0,174,12,1,0,0, + 0,175,176,5,119,0,0,176,177,5,104,0,0,177,178,5,105,0,0,178,179,5,108, + 0,0,179,180,5,101,0,0,180,14,1,0,0,0,181,182,5,114,0,0,182,183,5,101,0, + 0,183,184,5,112,0,0,184,185,5,101,0,0,185,186,5,97,0,0,186,187,5,116,0, + 0,187,16,1,0,0,0,188,189,5,117,0,0,189,190,5,110,0,0,190,191,5,116,0,0, + 191,192,5,105,0,0,192,193,5,108,0,0,193,18,1,0,0,0,194,195,5,102,0,0,195, + 196,5,111,0,0,196,197,5,114,0,0,197,20,1,0,0,0,198,199,5,44,0,0,199,22, + 1,0,0,0,200,201,5,105,0,0,201,202,5,110,0,0,202,24,1,0,0,0,203,204,5,102, + 0,0,204,205,5,117,0,0,205,206,5,110,0,0,206,207,5,99,0,0,207,208,5,116, + 0,0,208,209,5,105,0,0,209,210,5,111,0,0,210,211,5,110,0,0,211,26,1,0,0, + 0,212,213,5,108,0,0,213,214,5,111,0,0,214,215,5,99,0,0,215,216,5,97,0, + 0,216,217,5,108,0,0,217,28,1,0,0,0,218,219,5,105,0,0,219,220,5,102,0,0, + 220,30,1,0,0,0,221,222,5,116,0,0,222,223,5,104,0,0,223,224,5,101,0,0,224, + 225,5,110,0,0,225,32,1,0,0,0,226,227,5,101,0,0,227,228,5,108,0,0,228,229, + 5,115,0,0,229,230,5,101,0,0,230,231,5,105,0,0,231,232,5,102,0,0,232,34, + 1,0,0,0,233,234,5,101,0,0,234,235,5,108,0,0,235,236,5,115,0,0,236,237, + 5,101,0,0,237,36,1,0,0,0,238,239,5,114,0,0,239,240,5,101,0,0,240,241,5, + 116,0,0,241,242,5,117,0,0,242,243,5,114,0,0,243,244,5,110,0,0,244,38,1, + 0,0,0,245,246,5,58,0,0,246,247,5,58,0,0,247,40,1,0,0,0,248,249,5,46,0, + 0,249,42,1,0,0,0,250,251,5,58,0,0,251,44,1,0,0,0,252,253,5,110,0,0,253, + 254,5,105,0,0,254,255,5,108,0,0,255,46,1,0,0,0,256,257,5,102,0,0,257,258, + 5,97,0,0,258,259,5,108,0,0,259,260,5,115,0,0,260,261,5,101,0,0,261,48, + 1,0,0,0,262,263,5,116,0,0,263,264,5,114,0,0,264,265,5,117,0,0,265,266, + 5,101,0,0,266,50,1,0,0,0,267,268,5,46,0,0,268,269,5,46,0,0,269,270,5,46, + 0,0,270,52,1,0,0,0,271,272,5,40,0,0,272,54,1,0,0,0,273,274,5,41,0,0,274, + 56,1,0,0,0,275,276,5,91,0,0,276,58,1,0,0,0,277,278,5,93,0,0,278,60,1,0, + 0,0,279,280,5,123,0,0,280,62,1,0,0,0,281,282,5,125,0,0,282,64,1,0,0,0, + 283,284,5,111,0,0,284,285,5,114,0,0,285,66,1,0,0,0,286,287,5,97,0,0,287, + 288,5,110,0,0,288,289,5,100,0,0,289,68,1,0,0,0,290,291,5,60,0,0,291,70, + 1,0,0,0,292,293,5,62,0,0,293,72,1,0,0,0,294,295,5,60,0,0,295,296,5,61, + 0,0,296,74,1,0,0,0,297,298,5,62,0,0,298,299,5,61,0,0,299,76,1,0,0,0,300, + 301,5,126,0,0,301,302,5,61,0,0,302,78,1,0,0,0,303,304,5,61,0,0,304,305, + 5,61,0,0,305,80,1,0,0,0,306,307,5,46,0,0,307,308,5,46,0,0,308,82,1,0,0, + 0,309,310,5,43,0,0,310,84,1,0,0,0,311,312,5,45,0,0,312,86,1,0,0,0,313, + 314,5,42,0,0,314,88,1,0,0,0,315,316,5,47,0,0,316,90,1,0,0,0,317,318,5, + 37,0,0,318,92,1,0,0,0,319,320,5,47,0,0,320,321,5,47,0,0,321,94,1,0,0,0, + 322,323,5,38,0,0,323,96,1,0,0,0,324,325,5,124,0,0,325,98,1,0,0,0,326,327, + 5,126,0,0,327,100,1,0,0,0,328,329,5,60,0,0,329,330,5,60,0,0,330,102,1, + 0,0,0,331,332,5,62,0,0,332,333,5,62,0,0,333,104,1,0,0,0,334,335,5,110, + 0,0,335,336,5,111,0,0,336,337,5,116,0,0,337,106,1,0,0,0,338,339,5,35,0, + 0,339,108,1,0,0,0,340,341,5,94,0,0,341,110,1,0,0,0,342,346,7,0,0,0,343, + 345,7,1,0,0,344,343,1,0,0,0,345,348,1,0,0,0,346,344,1,0,0,0,346,347,1, + 0,0,0,347,112,1,0,0,0,348,346,1,0,0,0,349,354,5,34,0,0,350,353,3,133,66, + 0,351,353,8,2,0,0,352,350,1,0,0,0,352,351,1,0,0,0,353,356,1,0,0,0,354, + 352,1,0,0,0,354,355,1,0,0,0,355,357,1,0,0,0,356,354,1,0,0,0,357,358,5, + 34,0,0,358,114,1,0,0,0,359,364,5,39,0,0,360,363,3,133,66,0,361,363,8,3, + 0,0,362,360,1,0,0,0,362,361,1,0,0,0,363,366,1,0,0,0,364,362,1,0,0,0,364, + 365,1,0,0,0,365,367,1,0,0,0,366,364,1,0,0,0,367,368,5,39,0,0,368,116,1, + 0,0,0,369,370,5,91,0,0,370,371,3,119,59,0,371,372,5,93,0,0,372,118,1,0, + 0,0,373,374,5,61,0,0,374,375,3,119,59,0,375,376,5,61,0,0,376,386,1,0,0, + 0,377,381,5,91,0,0,378,380,9,0,0,0,379,378,1,0,0,0,380,383,1,0,0,0,381, + 382,1,0,0,0,381,379,1,0,0,0,382,384,1,0,0,0,383,381,1,0,0,0,384,386,5, + 93,0,0,385,373,1,0,0,0,385,377,1,0,0,0,386,120,1,0,0,0,387,389,3,141,70, + 0,388,387,1,0,0,0,389,390,1,0,0,0,390,388,1,0,0,0,390,391,1,0,0,0,391, + 122,1,0,0,0,392,393,5,48,0,0,393,395,7,4,0,0,394,396,3,143,71,0,395,394, + 1,0,0,0,396,397,1,0,0,0,397,395,1,0,0,0,397,398,1,0,0,0,398,124,1,0,0, + 0,399,401,3,141,70,0,400,399,1,0,0,0,401,402,1,0,0,0,402,400,1,0,0,0,402, + 403,1,0,0,0,403,404,1,0,0,0,404,408,5,46,0,0,405,407,3,141,70,0,406,405, + 1,0,0,0,407,410,1,0,0,0,408,406,1,0,0,0,408,409,1,0,0,0,409,412,1,0,0, + 0,410,408,1,0,0,0,411,413,3,129,64,0,412,411,1,0,0,0,412,413,1,0,0,0,413, + 431,1,0,0,0,414,416,5,46,0,0,415,417,3,141,70,0,416,415,1,0,0,0,417,418, + 1,0,0,0,418,416,1,0,0,0,418,419,1,0,0,0,419,421,1,0,0,0,420,422,3,129, + 64,0,421,420,1,0,0,0,421,422,1,0,0,0,422,431,1,0,0,0,423,425,3,141,70, + 0,424,423,1,0,0,0,425,426,1,0,0,0,426,424,1,0,0,0,426,427,1,0,0,0,427, + 428,1,0,0,0,428,429,3,129,64,0,429,431,1,0,0,0,430,400,1,0,0,0,430,414, + 1,0,0,0,430,424,1,0,0,0,431,126,1,0,0,0,432,433,5,48,0,0,433,435,7,4,0, + 0,434,436,3,143,71,0,435,434,1,0,0,0,436,437,1,0,0,0,437,435,1,0,0,0,437, + 438,1,0,0,0,438,439,1,0,0,0,439,443,5,46,0,0,440,442,3,143,71,0,441,440, + 1,0,0,0,442,445,1,0,0,0,443,441,1,0,0,0,443,444,1,0,0,0,444,447,1,0,0, + 0,445,443,1,0,0,0,446,448,3,131,65,0,447,446,1,0,0,0,447,448,1,0,0,0,448, + 470,1,0,0,0,449,450,5,48,0,0,450,451,7,4,0,0,451,453,5,46,0,0,452,454, + 3,143,71,0,453,452,1,0,0,0,454,455,1,0,0,0,455,453,1,0,0,0,455,456,1,0, + 0,0,456,458,1,0,0,0,457,459,3,131,65,0,458,457,1,0,0,0,458,459,1,0,0,0, + 459,470,1,0,0,0,460,461,5,48,0,0,461,463,7,4,0,0,462,464,3,143,71,0,463, + 462,1,0,0,0,464,465,1,0,0,0,465,463,1,0,0,0,465,466,1,0,0,0,466,467,1, + 0,0,0,467,468,3,131,65,0,468,470,1,0,0,0,469,432,1,0,0,0,469,449,1,0,0, + 0,469,460,1,0,0,0,470,128,1,0,0,0,471,473,7,5,0,0,472,474,7,6,0,0,473, + 472,1,0,0,0,473,474,1,0,0,0,474,476,1,0,0,0,475,477,3,141,70,0,476,475, + 1,0,0,0,477,478,1,0,0,0,478,476,1,0,0,0,478,479,1,0,0,0,479,130,1,0,0, + 0,480,482,7,7,0,0,481,483,7,6,0,0,482,481,1,0,0,0,482,483,1,0,0,0,483, + 485,1,0,0,0,484,486,3,141,70,0,485,484,1,0,0,0,486,487,1,0,0,0,487,485, + 1,0,0,0,487,488,1,0,0,0,488,132,1,0,0,0,489,490,5,92,0,0,490,500,7,8,0, + 0,491,493,5,92,0,0,492,494,5,13,0,0,493,492,1,0,0,0,493,494,1,0,0,0,494, + 495,1,0,0,0,495,500,5,10,0,0,496,500,3,135,67,0,497,500,3,137,68,0,498, + 500,3,139,69,0,499,489,1,0,0,0,499,491,1,0,0,0,499,496,1,0,0,0,499,497, + 1,0,0,0,499,498,1,0,0,0,500,134,1,0,0,0,501,502,5,92,0,0,502,513,3,141, + 70,0,503,504,5,92,0,0,504,505,3,141,70,0,505,506,3,141,70,0,506,513,1, + 0,0,0,507,508,5,92,0,0,508,509,7,9,0,0,509,510,3,141,70,0,510,511,3,141, + 70,0,511,513,1,0,0,0,512,501,1,0,0,0,512,503,1,0,0,0,512,507,1,0,0,0,513, + 136,1,0,0,0,514,515,5,92,0,0,515,516,5,120,0,0,516,517,3,143,71,0,517, + 518,3,143,71,0,518,138,1,0,0,0,519,520,5,92,0,0,520,521,5,117,0,0,521, + 522,5,123,0,0,522,524,1,0,0,0,523,525,3,143,71,0,524,523,1,0,0,0,525,526, + 1,0,0,0,526,524,1,0,0,0,526,527,1,0,0,0,527,528,1,0,0,0,528,529,5,125, + 0,0,529,140,1,0,0,0,530,531,7,10,0,0,531,142,1,0,0,0,532,533,7,11,0,0, + 533,144,1,0,0,0,534,535,5,45,0,0,535,536,5,45,0,0,536,537,5,91,0,0,537, + 538,1,0,0,0,538,539,3,119,59,0,539,540,5,93,0,0,540,541,1,0,0,0,541,542, + 6,72,0,0,542,146,1,0,0,0,543,544,5,45,0,0,544,545,5,45,0,0,545,575,1,0, + 0,0,546,576,1,0,0,0,547,551,5,91,0,0,548,550,5,61,0,0,549,548,1,0,0,0, + 550,553,1,0,0,0,551,549,1,0,0,0,551,552,1,0,0,0,552,576,1,0,0,0,553,551, + 1,0,0,0,554,558,5,91,0,0,555,557,5,61,0,0,556,555,1,0,0,0,557,560,1,0, + 0,0,558,556,1,0,0,0,558,559,1,0,0,0,559,561,1,0,0,0,560,558,1,0,0,0,561, + 565,8,12,0,0,562,564,8,13,0,0,563,562,1,0,0,0,564,567,1,0,0,0,565,563, + 1,0,0,0,565,566,1,0,0,0,566,576,1,0,0,0,567,565,1,0,0,0,568,572,8,14,0, + 0,569,571,8,13,0,0,570,569,1,0,0,0,571,574,1,0,0,0,572,570,1,0,0,0,572, + 573,1,0,0,0,573,576,1,0,0,0,574,572,1,0,0,0,575,546,1,0,0,0,575,547,1, + 0,0,0,575,554,1,0,0,0,575,568,1,0,0,0,576,580,1,0,0,0,577,578,5,13,0,0, + 578,581,5,10,0,0,579,581,7,15,0,0,580,577,1,0,0,0,580,579,1,0,0,0,581, + 582,1,0,0,0,582,583,6,73,0,0,583,148,1,0,0,0,584,586,7,16,0,0,585,584, + 1,0,0,0,586,587,1,0,0,0,587,585,1,0,0,0,587,588,1,0,0,0,588,589,1,0,0, + 0,589,590,6,74,1,0,590,150,1,0,0,0,591,592,5,35,0,0,592,596,5,33,0,0,593, + 595,8,13,0,0,594,593,1,0,0,0,595,598,1,0,0,0,596,594,1,0,0,0,596,597,1, + 0,0,0,597,599,1,0,0,0,598,596,1,0,0,0,599,600,6,75,0,0,600,152,1,0,0,0, + 40,0,346,352,354,362,364,381,385,390,397,402,408,412,418,421,426,430,437, + 443,447,455,458,465,469,473,478,482,487,493,499,512,526,551,558,565,572, + 575,580,587,596,2,0,1,0,6,0,0 + }; + + public static readonly ATN _ATN = + new ATNDeserializer().Deserialize(_serializedATN); + + +} diff --git a/bot/src/Syntax/Parser/LuaParser.cs b/bot/src/Syntax/Parser/LuaParser.cs new file mode 100644 index 0000000..a735a17 --- /dev/null +++ b/bot/src/Syntax/Parser/LuaParser.cs @@ -0,0 +1,3207 @@ +// Unreachable code detected +#pragma warning disable 0162 +// The variable '...' is assigned but its value is never used +#pragma warning disable 0219 +// Missing XML comment for publicly visible type or member '...' +#pragma warning disable 1591 +// Ambiguous reference in cref attribute +#pragma warning disable 419 + +using Antlr4.Runtime; +using Antlr4.Runtime.Atn; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; +using DFA = Antlr4.Runtime.Dfa.DFA; + +namespace MoonsecDeobfuscator.Syntax.Parser; + +[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")] +[System.CLSCompliant(false)] +public partial class LuaParser : Antlr4.Runtime.Parser { + protected static DFA[] decisionToDFA; + protected static PredictionContextCache sharedContextCache = new PredictionContextCache(); + public const int + T__0=1, T__1=2, T__2=3, T__3=4, T__4=5, T__5=6, T__6=7, T__7=8, T__8=9, + T__9=10, T__10=11, T__11=12, T__12=13, T__13=14, T__14=15, T__15=16, T__16=17, + T__17=18, T__18=19, T__19=20, T__20=21, T__21=22, T__22=23, T__23=24, + T__24=25, T__25=26, T__26=27, T__27=28, T__28=29, T__29=30, T__30=31, + T__31=32, T__32=33, T__33=34, T__34=35, T__35=36, T__36=37, T__37=38, + T__38=39, T__39=40, T__40=41, T__41=42, T__42=43, T__43=44, T__44=45, + T__45=46, T__46=47, T__47=48, T__48=49, T__49=50, T__50=51, T__51=52, + T__52=53, T__53=54, T__54=55, NAME=56, NORMALSTRING=57, CHARSTRING=58, + LONGSTRING=59, INT=60, HEX=61, FLOAT=62, HEX_FLOAT=63, COMMENT=64, LINE_COMMENT=65, + WS=66, SHEBANG=67; + public const int + RULE_chunk = 0, RULE_block = 1, RULE_stat = 2, RULE_ifstmt = 3, RULE_elseifstmt = 4, + RULE_elsestmt = 5, RULE_retstat = 6, RULE_label = 7, RULE_funcname = 8, + RULE_varlist = 9, RULE_namelist = 10, RULE_explist = 11, RULE_exp = 12, + RULE_prefixexp = 13, RULE_functioncall = 14, RULE_varOrExp = 15, RULE_var = 16, + RULE_varSuffix = 17, RULE_nameAndArgs = 18, RULE_args = 19, RULE_functiondef = 20, + RULE_funcbody = 21, RULE_parlist = 22, RULE_tableconstructor = 23, RULE_fieldlist = 24, + RULE_field = 25, RULE_fieldsep = 26, RULE_operatorOr = 27, RULE_operatorAnd = 28, + RULE_operatorComparison = 29, RULE_operatorStrcat = 30, RULE_operatorAddSub = 31, + RULE_operatorMulDivMod = 32, RULE_operatorBitwise = 33, RULE_operatorUnary = 34, + RULE_operatorPower = 35, RULE_number = 36, RULE_string = 37; + public static readonly string[] ruleNames = { + "chunk", "block", "stat", "ifstmt", "elseifstmt", "elsestmt", "retstat", + "label", "funcname", "varlist", "namelist", "explist", "exp", "prefixexp", + "functioncall", "varOrExp", "var", "varSuffix", "nameAndArgs", "args", + "functiondef", "funcbody", "parlist", "tableconstructor", "fieldlist", + "field", "fieldsep", "operatorOr", "operatorAnd", "operatorComparison", + "operatorStrcat", "operatorAddSub", "operatorMulDivMod", "operatorBitwise", + "operatorUnary", "operatorPower", "number", "string" + }; + + private static readonly string[] _LiteralNames = { + null, "';'", "'='", "'break'", "'goto'", "'do'", "'end'", "'while'", "'repeat'", + "'until'", "'for'", "','", "'in'", "'function'", "'local'", "'if'", "'then'", + "'elseif'", "'else'", "'return'", "'::'", "'.'", "':'", "'nil'", "'false'", + "'true'", "'...'", "'('", "')'", "'['", "']'", "'{'", "'}'", "'or'", "'and'", + "'<'", "'>'", "'<='", "'>='", "'~='", "'=='", "'..'", "'+'", "'-'", "'*'", + "'/'", "'%'", "'//'", "'&'", "'|'", "'~'", "'<<'", "'>>'", "'not'", "'#'", + "'^'" + }; + private static readonly string[] _SymbolicNames = { + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "NAME", "NORMALSTRING", + "CHARSTRING", "LONGSTRING", "INT", "HEX", "FLOAT", "HEX_FLOAT", "COMMENT", + "LINE_COMMENT", "WS", "SHEBANG" + }; + public static readonly IVocabulary DefaultVocabulary = new Vocabulary(_LiteralNames, _SymbolicNames); + + [NotNull] + public override IVocabulary Vocabulary + { + get + { + return DefaultVocabulary; + } + } + + public override string GrammarFileName { get { return "Lua.g4"; } } + + public override string[] RuleNames { get { return ruleNames; } } + + public override int[] SerializedAtn { get { return _serializedATN; } } + + static LuaParser() { + decisionToDFA = new DFA[_ATN.NumberOfDecisions]; + for (int i = 0; i < _ATN.NumberOfDecisions; i++) { + decisionToDFA[i] = new DFA(_ATN.GetDecisionState(i), i); + } + } + + public LuaParser(ITokenStream input) : this(input, Console.Out, Console.Error) { } + + public LuaParser(ITokenStream input, TextWriter output, TextWriter errorOutput) + : base(input, output, errorOutput) + { + Interpreter = new ParserATNSimulator(this, _ATN, decisionToDFA, sharedContextCache); + } + + public partial class ChunkContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode Eof() { return GetToken(LuaParser.Eof, 0); } + public ChunkContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_chunk; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitChunk(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ChunkContext chunk() { + ChunkContext _localctx = new ChunkContext(Context, State); + EnterRule(_localctx, 0, RULE_chunk); + try { + EnterOuterAlt(_localctx, 1); + { + State = 76; + block(); + State = 77; + Match(Eof); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class BlockContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public StatContext[] stat() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public StatContext stat(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public RetstatContext retstat() { + return GetRuleContext(0); + } + public BlockContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_block; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitBlock(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public BlockContext block() { + BlockContext _localctx = new BlockContext(Context, State); + EnterRule(_localctx, 2, RULE_block); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 82; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + while ((((_la) & ~0x3f) == 0 && ((1L << _la) & 72057594173253050L) != 0)) { + { + { + State = 79; + stat(); + } + } + State = 84; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + } + State = 86; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__18) { + { + State = 85; + retstat(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class StatContext : ParserRuleContext { + public StatContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_stat; } } + + public StatContext() { } + public virtual void CopyFrom(StatContext context) { + base.CopyFrom(context); + } + } + public partial class StatGenericForContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public NamelistContext namelist() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExplistContext explist() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public StatGenericForContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatGenericFor(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatFunctionContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public FuncnameContext funcname() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public FuncbodyContext funcbody() { + return GetRuleContext(0); + } + public StatFunctionContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatFunction(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatBreakContext : StatContext { + public StatBreakContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatBreak(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatSemiContext : StatContext { + public StatSemiContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatSemi(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatLocalFunctionContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + [System.Diagnostics.DebuggerNonUserCode] public FuncbodyContext funcbody() { + return GetRuleContext(0); + } + public StatLocalFunctionContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatLocalFunction(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatLocalDeclareContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public NamelistContext namelist() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExplistContext explist() { + return GetRuleContext(0); + } + public StatLocalDeclareContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatLocalDeclare(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatCallContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public FunctioncallContext functioncall() { + return GetRuleContext(0); + } + public StatCallContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatCall(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatLabelContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public LabelContext label() { + return GetRuleContext(0); + } + public StatLabelContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatLabel(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatDoContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public StatDoContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatDo(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatWhileContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public StatWhileContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatWhile(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatGotoContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + public StatGotoContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatGoto(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatAssignContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public VarlistContext varlist() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExplistContext explist() { + return GetRuleContext(0); + } + public StatAssignContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatAssign(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatRepeatContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + public StatRepeatContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatRepeat(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatIfContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public IfstmtContext ifstmt() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ElseifstmtContext elseifstmt() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ElsestmtContext elsestmt() { + return GetRuleContext(0); + } + public StatIfContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatIf(this); + else return visitor.VisitChildren(this); + } + } + public partial class StatNumericForContext : StatContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public StatNumericForContext(StatContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitStatNumericFor(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public StatContext stat() { + StatContext _localctx = new StatContext(Context, State); + EnterRule(_localctx, 4, RULE_stat); + int _la; + try { + State = 154; + ErrorHandler.Sync(this); + switch ( Interpreter.AdaptivePredict(TokenStream,4,Context) ) { + case 1: + _localctx = new StatSemiContext(_localctx); + EnterOuterAlt(_localctx, 1); + { + State = 88; + Match(T__0); + } + break; + case 2: + _localctx = new StatAssignContext(_localctx); + EnterOuterAlt(_localctx, 2); + { + State = 89; + varlist(); + State = 90; + Match(T__1); + State = 91; + explist(); + } + break; + case 3: + _localctx = new StatCallContext(_localctx); + EnterOuterAlt(_localctx, 3); + { + State = 93; + functioncall(); + } + break; + case 4: + _localctx = new StatLabelContext(_localctx); + EnterOuterAlt(_localctx, 4); + { + State = 94; + label(); + } + break; + case 5: + _localctx = new StatBreakContext(_localctx); + EnterOuterAlt(_localctx, 5); + { + State = 95; + Match(T__2); + } + break; + case 6: + _localctx = new StatGotoContext(_localctx); + EnterOuterAlt(_localctx, 6); + { + State = 96; + Match(T__3); + State = 97; + Match(NAME); + } + break; + case 7: + _localctx = new StatDoContext(_localctx); + EnterOuterAlt(_localctx, 7); + { + State = 98; + Match(T__4); + State = 99; + block(); + State = 100; + Match(T__5); + } + break; + case 8: + _localctx = new StatWhileContext(_localctx); + EnterOuterAlt(_localctx, 8); + { + State = 102; + Match(T__6); + State = 103; + exp(0); + State = 104; + Match(T__4); + State = 105; + block(); + State = 106; + Match(T__5); + } + break; + case 9: + _localctx = new StatRepeatContext(_localctx); + EnterOuterAlt(_localctx, 9); + { + State = 108; + Match(T__7); + State = 109; + block(); + State = 110; + Match(T__8); + State = 111; + exp(0); + } + break; + case 10: + _localctx = new StatIfContext(_localctx); + EnterOuterAlt(_localctx, 10); + { + State = 113; + ifstmt(); + State = 114; + elseifstmt(); + State = 115; + elsestmt(); + State = 116; + Match(T__5); + } + break; + case 11: + _localctx = new StatNumericForContext(_localctx); + EnterOuterAlt(_localctx, 11); + { + State = 118; + Match(T__9); + State = 119; + Match(NAME); + State = 120; + Match(T__1); + State = 121; + exp(0); + State = 122; + Match(T__10); + State = 123; + exp(0); + State = 126; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__10) { + { + State = 124; + Match(T__10); + State = 125; + exp(0); + } + } + + State = 128; + Match(T__4); + State = 129; + block(); + State = 130; + Match(T__5); + } + break; + case 12: + _localctx = new StatGenericForContext(_localctx); + EnterOuterAlt(_localctx, 12); + { + State = 132; + Match(T__9); + State = 133; + namelist(); + State = 134; + Match(T__11); + State = 135; + explist(); + State = 136; + Match(T__4); + State = 137; + block(); + State = 138; + Match(T__5); + } + break; + case 13: + _localctx = new StatFunctionContext(_localctx); + EnterOuterAlt(_localctx, 13); + { + State = 140; + Match(T__12); + State = 141; + funcname(); + State = 142; + funcbody(); + } + break; + case 14: + _localctx = new StatLocalFunctionContext(_localctx); + EnterOuterAlt(_localctx, 14); + { + State = 144; + Match(T__13); + State = 145; + Match(T__12); + State = 146; + Match(NAME); + State = 147; + funcbody(); + } + break; + case 15: + _localctx = new StatLocalDeclareContext(_localctx); + EnterOuterAlt(_localctx, 15); + { + State = 148; + Match(T__13); + State = 149; + namelist(); + State = 152; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__1) { + { + State = 150; + Match(T__1); + State = 151; + explist(); + } + } + + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class IfstmtContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public IfstmtContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_ifstmt; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitIfstmt(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public IfstmtContext ifstmt() { + IfstmtContext _localctx = new IfstmtContext(Context, State); + EnterRule(_localctx, 6, RULE_ifstmt); + try { + EnterOuterAlt(_localctx, 1); + { + State = 156; + Match(T__14); + State = 157; + exp(0); + State = 158; + Match(T__15); + State = 159; + block(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ElseifstmtContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext[] block() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block(int i) { + return GetRuleContext(i); + } + public ElseifstmtContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_elseifstmt; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitElseifstmt(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ElseifstmtContext elseifstmt() { + ElseifstmtContext _localctx = new ElseifstmtContext(Context, State); + EnterRule(_localctx, 8, RULE_elseifstmt); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 168; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + while (_la==T__16) { + { + { + State = 161; + Match(T__16); + State = 162; + exp(0); + State = 163; + Match(T__15); + State = 164; + block(); + } + } + State = 170; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ElsestmtContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + public ElsestmtContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_elsestmt; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitElsestmt(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ElsestmtContext elsestmt() { + ElsestmtContext _localctx = new ElsestmtContext(Context, State); + EnterRule(_localctx, 10, RULE_elsestmt); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 173; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__17) { + { + State = 171; + Match(T__17); + State = 172; + block(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class RetstatContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExplistContext explist() { + return GetRuleContext(0); + } + public RetstatContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_retstat; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitRetstat(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public RetstatContext retstat() { + RetstatContext _localctx = new RetstatContext(Context, State); + EnterRule(_localctx, 12, RULE_retstat); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 175; + Match(T__18); + State = 177; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & -43901297866301440L) != 0)) { + { + State = 176; + explist(); + } + } + + State = 180; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__0) { + { + State = 179; + Match(T__0); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class LabelContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + public LabelContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_label; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitLabel(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public LabelContext label() { + LabelContext _localctx = new LabelContext(Context, State); + EnterRule(_localctx, 14, RULE_label); + try { + EnterOuterAlt(_localctx, 1); + { + State = 182; + Match(T__19); + State = 183; + Match(NAME); + State = 184; + Match(T__19); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FuncnameContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode[] NAME() { return GetTokens(LuaParser.NAME); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME(int i) { + return GetToken(LuaParser.NAME, i); + } + public FuncnameContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_funcname; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFuncname(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FuncnameContext funcname() { + FuncnameContext _localctx = new FuncnameContext(Context, State); + EnterRule(_localctx, 16, RULE_funcname); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 186; + Match(NAME); + State = 191; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + while (_la==T__20) { + { + { + State = 187; + Match(T__20); + State = 188; + Match(NAME); + } + } + State = 193; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + } + State = 196; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__21) { + { + State = 194; + Match(T__21); + State = 195; + Match(NAME); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class VarlistContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public VarContext[] var() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public VarContext var(int i) { + return GetRuleContext(i); + } + public VarlistContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_varlist; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitVarlist(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public VarlistContext varlist() { + VarlistContext _localctx = new VarlistContext(Context, State); + EnterRule(_localctx, 18, RULE_varlist); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 198; + var(); + State = 203; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + while (_la==T__10) { + { + { + State = 199; + Match(T__10); + State = 200; + var(); + } + } + State = 205; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class NamelistContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode[] NAME() { return GetTokens(LuaParser.NAME); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME(int i) { + return GetToken(LuaParser.NAME, i); + } + public NamelistContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_namelist; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitNamelist(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public NamelistContext namelist() { + NamelistContext _localctx = new NamelistContext(Context, State); + EnterRule(_localctx, 20, RULE_namelist); + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 206; + Match(NAME); + State = 211; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,12,Context); + while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + State = 207; + Match(T__10); + State = 208; + Match(NAME); + } + } + } + State = 213; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,12,Context); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ExplistContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + public ExplistContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_explist; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExplist(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ExplistContext explist() { + ExplistContext _localctx = new ExplistContext(Context, State); + EnterRule(_localctx, 22, RULE_explist); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 214; + exp(0); + State = 219; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + while (_la==T__10) { + { + { + State = 215; + Match(T__10); + State = 216; + exp(0); + } + } + State = 221; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ExpContext : ParserRuleContext { + public ExpContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_exp; } } + + public ExpContext() { } + public virtual void CopyFrom(ExpContext context) { + base.CopyFrom(context); + } + } + public partial class ExpNumberContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public NumberContext number() { + return GetRuleContext(0); + } + public ExpNumberContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpNumber(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpTrueContext : ExpContext { + public ExpTrueContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpTrue(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpOrContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorOrContext operatorOr() { + return GetRuleContext(0); + } + public ExpOrContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpOr(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpBitwiseContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorBitwiseContext operatorBitwise() { + return GetRuleContext(0); + } + public ExpBitwiseContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpBitwise(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpMulDivModContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorMulDivModContext operatorMulDivMod() { + return GetRuleContext(0); + } + public ExpMulDivModContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpMulDivMod(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpFalseContext : ExpContext { + public ExpFalseContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpFalse(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpStringContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public StringContext @string() { + return GetRuleContext(0); + } + public ExpStringContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpString(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpPrefixContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public PrefixexpContext prefixexp() { + return GetRuleContext(0); + } + public ExpPrefixContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpPrefix(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpUnaryContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public OperatorUnaryContext operatorUnary() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + public ExpUnaryContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpUnary(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpAndContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorAndContext operatorAnd() { + return GetRuleContext(0); + } + public ExpAndContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpAnd(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpPowContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorPowerContext operatorPower() { + return GetRuleContext(0); + } + public ExpPowContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpPow(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpFunctionContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public FunctiondefContext functiondef() { + return GetRuleContext(0); + } + public ExpFunctionContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpFunction(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpCompareContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorComparisonContext operatorComparison() { + return GetRuleContext(0); + } + public ExpCompareContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpCompare(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpConcatContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorStrcatContext operatorStrcat() { + return GetRuleContext(0); + } + public ExpConcatContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpConcat(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpNilContext : ExpContext { + public ExpNilContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpNil(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpAddSubContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public OperatorAddSubContext operatorAddSub() { + return GetRuleContext(0); + } + public ExpAddSubContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpAddSub(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpVarArgContext : ExpContext { + public ExpVarArgContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpVarArg(this); + else return visitor.VisitChildren(this); + } + } + public partial class ExpTableContext : ExpContext { + [System.Diagnostics.DebuggerNonUserCode] public TableconstructorContext tableconstructor() { + return GetRuleContext(0); + } + public ExpTableContext(ExpContext context) { CopyFrom(context); } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitExpTable(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ExpContext exp() { + return exp(0); + } + + private ExpContext exp(int _p) { + ParserRuleContext _parentctx = Context; + int _parentState = State; + ExpContext _localctx = new ExpContext(Context, _parentState); + ExpContext _prevctx = _localctx; + int _startState = 24; + EnterRecursionRule(_localctx, 24, RULE_exp, _p); + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 235; + ErrorHandler.Sync(this); + switch (TokenStream.LA(1)) { + case T__22: + { + _localctx = new ExpNilContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + + State = 223; + Match(T__22); + } + break; + case T__23: + { + _localctx = new ExpFalseContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 224; + Match(T__23); + } + break; + case T__24: + { + _localctx = new ExpTrueContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 225; + Match(T__24); + } + break; + case INT: + case HEX: + case FLOAT: + case HEX_FLOAT: + { + _localctx = new ExpNumberContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 226; + number(); + } + break; + case NORMALSTRING: + case CHARSTRING: + case LONGSTRING: + { + _localctx = new ExpStringContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 227; + @string(); + } + break; + case T__25: + { + _localctx = new ExpVarArgContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 228; + Match(T__25); + } + break; + case T__12: + { + _localctx = new ExpFunctionContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 229; + functiondef(); + } + break; + case T__26: + case NAME: + { + _localctx = new ExpPrefixContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 230; + prefixexp(); + } + break; + case T__30: + { + _localctx = new ExpTableContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 231; + tableconstructor(); + } + break; + case T__42: + case T__49: + case T__52: + case T__53: + { + _localctx = new ExpUnaryContext(_localctx); + Context = _localctx; + _prevctx = _localctx; + State = 232; + operatorUnary(); + State = 233; + exp(8); + } + break; + default: + throw new NoViableAltException(this); + } + Context.Stop = TokenStream.LT(-1); + State = 271; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,16,Context); + while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + if ( ParseListeners!=null ) + TriggerExitRuleEvent(); + _prevctx = _localctx; + { + State = 269; + ErrorHandler.Sync(this); + switch ( Interpreter.AdaptivePredict(TokenStream,15,Context) ) { + case 1: + { + _localctx = new ExpPowContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 237; + if (!(Precpred(Context, 9))) throw new FailedPredicateException(this, "Precpred(Context, 9)"); + State = 238; + operatorPower(); + State = 239; + exp(9); + } + break; + case 2: + { + _localctx = new ExpMulDivModContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 241; + if (!(Precpred(Context, 7))) throw new FailedPredicateException(this, "Precpred(Context, 7)"); + State = 242; + operatorMulDivMod(); + State = 243; + exp(8); + } + break; + case 3: + { + _localctx = new ExpAddSubContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 245; + if (!(Precpred(Context, 6))) throw new FailedPredicateException(this, "Precpred(Context, 6)"); + State = 246; + operatorAddSub(); + State = 247; + exp(7); + } + break; + case 4: + { + _localctx = new ExpConcatContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 249; + if (!(Precpred(Context, 5))) throw new FailedPredicateException(this, "Precpred(Context, 5)"); + State = 250; + operatorStrcat(); + State = 251; + exp(5); + } + break; + case 5: + { + _localctx = new ExpCompareContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 253; + if (!(Precpred(Context, 4))) throw new FailedPredicateException(this, "Precpred(Context, 4)"); + State = 254; + operatorComparison(); + State = 255; + exp(5); + } + break; + case 6: + { + _localctx = new ExpAndContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 257; + if (!(Precpred(Context, 3))) throw new FailedPredicateException(this, "Precpred(Context, 3)"); + State = 258; + operatorAnd(); + State = 259; + exp(4); + } + break; + case 7: + { + _localctx = new ExpOrContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 261; + if (!(Precpred(Context, 2))) throw new FailedPredicateException(this, "Precpred(Context, 2)"); + State = 262; + operatorOr(); + State = 263; + exp(3); + } + break; + case 8: + { + _localctx = new ExpBitwiseContext(new ExpContext(_parentctx, _parentState)); + PushNewRecursionContext(_localctx, _startState, RULE_exp); + State = 265; + if (!(Precpred(Context, 1))) throw new FailedPredicateException(this, "Precpred(Context, 1)"); + State = 266; + operatorBitwise(); + State = 267; + exp(2); + } + break; + } + } + } + State = 273; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,16,Context); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + UnrollRecursionContexts(_parentctx); + } + return _localctx; + } + + public partial class PrefixexpContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public VarOrExpContext varOrExp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public NameAndArgsContext[] nameAndArgs() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public NameAndArgsContext nameAndArgs(int i) { + return GetRuleContext(i); + } + public PrefixexpContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_prefixexp; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitPrefixexp(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public PrefixexpContext prefixexp() { + PrefixexpContext _localctx = new PrefixexpContext(Context, State); + EnterRule(_localctx, 26, RULE_prefixexp); + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 274; + varOrExp(); + State = 278; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,17,Context); + while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + State = 275; + nameAndArgs(); + } + } + } + State = 280; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,17,Context); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FunctioncallContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public VarOrExpContext varOrExp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public NameAndArgsContext[] nameAndArgs() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public NameAndArgsContext nameAndArgs(int i) { + return GetRuleContext(i); + } + public FunctioncallContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_functioncall; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFunctioncall(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FunctioncallContext functioncall() { + FunctioncallContext _localctx = new FunctioncallContext(Context, State); + EnterRule(_localctx, 28, RULE_functioncall); + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 281; + varOrExp(); + State = 283; + ErrorHandler.Sync(this); + _alt = 1; + do { + switch (_alt) { + case 1: + { + { + State = 282; + nameAndArgs(); + } + } + break; + default: + throw new NoViableAltException(this); + } + State = 285; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,18,Context); + } while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class VarOrExpContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public VarContext var() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + public VarOrExpContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_varOrExp; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitVarOrExp(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public VarOrExpContext varOrExp() { + VarOrExpContext _localctx = new VarOrExpContext(Context, State); + EnterRule(_localctx, 30, RULE_varOrExp); + try { + State = 292; + ErrorHandler.Sync(this); + switch ( Interpreter.AdaptivePredict(TokenStream,19,Context) ) { + case 1: + EnterOuterAlt(_localctx, 1); + { + State = 287; + var(); + } + break; + case 2: + EnterOuterAlt(_localctx, 2); + { + State = 288; + Match(T__26); + State = 289; + exp(0); + State = 290; + Match(T__27); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class VarContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public VarSuffixContext[] varSuffix() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public VarSuffixContext varSuffix(int i) { + return GetRuleContext(i); + } + public VarContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_var; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitVar(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public VarContext var() { + VarContext _localctx = new VarContext(Context, State); + EnterRule(_localctx, 32, RULE_var); + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 300; + ErrorHandler.Sync(this); + switch (TokenStream.LA(1)) { + case NAME: + { + State = 294; + Match(NAME); + } + break; + case T__26: + { + State = 295; + Match(T__26); + State = 296; + exp(0); + State = 297; + Match(T__27); + State = 298; + varSuffix(); + } + break; + default: + throw new NoViableAltException(this); + } + State = 305; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,21,Context); + while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + State = 302; + varSuffix(); + } + } + } + State = 307; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,21,Context); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class VarSuffixContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + public VarSuffixContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_varSuffix; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitVarSuffix(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public VarSuffixContext varSuffix() { + VarSuffixContext _localctx = new VarSuffixContext(Context, State); + EnterRule(_localctx, 34, RULE_varSuffix); + try { + State = 314; + ErrorHandler.Sync(this); + switch (TokenStream.LA(1)) { + case T__28: + EnterOuterAlt(_localctx, 1); + { + State = 308; + Match(T__28); + State = 309; + exp(0); + State = 310; + Match(T__29); + } + break; + case T__20: + EnterOuterAlt(_localctx, 2); + { + State = 312; + Match(T__20); + State = 313; + Match(NAME); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class NameAndArgsContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ArgsContext args() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + public NameAndArgsContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_nameAndArgs; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitNameAndArgs(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public NameAndArgsContext nameAndArgs() { + NameAndArgsContext _localctx = new NameAndArgsContext(Context, State); + EnterRule(_localctx, 36, RULE_nameAndArgs); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 318; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__21) { + { + State = 316; + Match(T__21); + State = 317; + Match(NAME); + } + } + + State = 320; + args(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ArgsContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExplistContext explist() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public TableconstructorContext tableconstructor() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public StringContext @string() { + return GetRuleContext(0); + } + public ArgsContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_args; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitArgs(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ArgsContext args() { + ArgsContext _localctx = new ArgsContext(Context, State); + EnterRule(_localctx, 38, RULE_args); + int _la; + try { + State = 329; + ErrorHandler.Sync(this); + switch (TokenStream.LA(1)) { + case T__26: + EnterOuterAlt(_localctx, 1); + { + State = 322; + Match(T__26); + State = 324; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & -43901297866301440L) != 0)) { + { + State = 323; + explist(); + } + } + + State = 326; + Match(T__27); + } + break; + case T__30: + EnterOuterAlt(_localctx, 2); + { + State = 327; + tableconstructor(); + } + break; + case NORMALSTRING: + case CHARSTRING: + case LONGSTRING: + EnterOuterAlt(_localctx, 3); + { + State = 328; + @string(); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FunctiondefContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public FuncbodyContext funcbody() { + return GetRuleContext(0); + } + public FunctiondefContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_functiondef; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFunctiondef(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FunctiondefContext functiondef() { + FunctiondefContext _localctx = new FunctiondefContext(Context, State); + EnterRule(_localctx, 40, RULE_functiondef); + try { + EnterOuterAlt(_localctx, 1); + { + State = 331; + Match(T__12); + State = 332; + funcbody(); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FuncbodyContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public BlockContext block() { + return GetRuleContext(0); + } + [System.Diagnostics.DebuggerNonUserCode] public ParlistContext parlist() { + return GetRuleContext(0); + } + public FuncbodyContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_funcbody; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFuncbody(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FuncbodyContext funcbody() { + FuncbodyContext _localctx = new FuncbodyContext(Context, State); + EnterRule(_localctx, 42, RULE_funcbody); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 334; + Match(T__26); + State = 336; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__25 || _la==NAME) { + { + State = 335; + parlist(); + } + } + + State = 338; + Match(T__27); + State = 339; + block(); + State = 340; + Match(T__5); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class ParlistContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public NamelistContext namelist() { + return GetRuleContext(0); + } + public ParlistContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_parlist; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitParlist(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public ParlistContext parlist() { + ParlistContext _localctx = new ParlistContext(Context, State); + EnterRule(_localctx, 44, RULE_parlist); + int _la; + try { + State = 348; + ErrorHandler.Sync(this); + switch (TokenStream.LA(1)) { + case NAME: + EnterOuterAlt(_localctx, 1); + { + State = 342; + namelist(); + State = 345; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__10) { + { + State = 343; + Match(T__10); + State = 344; + Match(T__25); + } + } + + } + break; + case T__25: + EnterOuterAlt(_localctx, 2); + { + State = 347; + Match(T__25); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class TableconstructorContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public FieldlistContext fieldlist() { + return GetRuleContext(0); + } + public TableconstructorContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_tableconstructor; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitTableconstructor(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public TableconstructorContext tableconstructor() { + TableconstructorContext _localctx = new TableconstructorContext(Context, State); + EnterRule(_localctx, 46, RULE_tableconstructor); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 350; + Match(T__30); + State = 352; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & -43901297329430528L) != 0)) { + { + State = 351; + fieldlist(); + } + } + + State = 354; + Match(T__31); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FieldlistContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public FieldContext[] field() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public FieldContext field(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public FieldsepContext[] fieldsep() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public FieldsepContext fieldsep(int i) { + return GetRuleContext(i); + } + public FieldlistContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_fieldlist; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFieldlist(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FieldlistContext fieldlist() { + FieldlistContext _localctx = new FieldlistContext(Context, State); + EnterRule(_localctx, 48, RULE_fieldlist); + int _la; + try { + int _alt; + EnterOuterAlt(_localctx, 1); + { + State = 356; + field(); + State = 362; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,30,Context); + while ( _alt!=2 && _alt!=global::Antlr4.Runtime.Atn.ATN.INVALID_ALT_NUMBER ) { + if ( _alt==1 ) { + { + { + State = 357; + fieldsep(); + State = 358; + field(); + } + } + } + State = 364; + ErrorHandler.Sync(this); + _alt = Interpreter.AdaptivePredict(TokenStream,30,Context); + } + State = 366; + ErrorHandler.Sync(this); + _la = TokenStream.LA(1); + if (_la==T__0 || _la==T__10) { + { + State = 365; + fieldsep(); + } + } + + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FieldContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ExpContext[] exp() { + return GetRuleContexts(); + } + [System.Diagnostics.DebuggerNonUserCode] public ExpContext exp(int i) { + return GetRuleContext(i); + } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NAME() { return GetToken(LuaParser.NAME, 0); } + public FieldContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_field; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitField(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FieldContext field() { + FieldContext _localctx = new FieldContext(Context, State); + EnterRule(_localctx, 50, RULE_field); + try { + State = 378; + ErrorHandler.Sync(this); + switch ( Interpreter.AdaptivePredict(TokenStream,32,Context) ) { + case 1: + EnterOuterAlt(_localctx, 1); + { + State = 368; + Match(T__28); + State = 369; + exp(0); + State = 370; + Match(T__29); + State = 371; + Match(T__1); + State = 372; + exp(0); + } + break; + case 2: + EnterOuterAlt(_localctx, 2); + { + State = 374; + Match(NAME); + State = 375; + Match(T__1); + State = 376; + exp(0); + } + break; + case 3: + EnterOuterAlt(_localctx, 3); + { + State = 377; + exp(0); + } + break; + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class FieldsepContext : ParserRuleContext { + public FieldsepContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_fieldsep; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitFieldsep(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public FieldsepContext fieldsep() { + FieldsepContext _localctx = new FieldsepContext(Context, State); + EnterRule(_localctx, 52, RULE_fieldsep); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 380; + _la = TokenStream.LA(1); + if ( !(_la==T__0 || _la==T__10) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorOrContext : ParserRuleContext { + public OperatorOrContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorOr; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorOr(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorOrContext operatorOr() { + OperatorOrContext _localctx = new OperatorOrContext(Context, State); + EnterRule(_localctx, 54, RULE_operatorOr); + try { + EnterOuterAlt(_localctx, 1); + { + State = 382; + Match(T__32); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorAndContext : ParserRuleContext { + public OperatorAndContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorAnd; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorAnd(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorAndContext operatorAnd() { + OperatorAndContext _localctx = new OperatorAndContext(Context, State); + EnterRule(_localctx, 56, RULE_operatorAnd); + try { + EnterOuterAlt(_localctx, 1); + { + State = 384; + Match(T__33); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorComparisonContext : ParserRuleContext { + public OperatorComparisonContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorComparison; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorComparison(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorComparisonContext operatorComparison() { + OperatorComparisonContext _localctx = new OperatorComparisonContext(Context, State); + EnterRule(_localctx, 58, RULE_operatorComparison); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 386; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 2164663517184L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorStrcatContext : ParserRuleContext { + public OperatorStrcatContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorStrcat; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorStrcat(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorStrcatContext operatorStrcat() { + OperatorStrcatContext _localctx = new OperatorStrcatContext(Context, State); + EnterRule(_localctx, 60, RULE_operatorStrcat); + try { + EnterOuterAlt(_localctx, 1); + { + State = 388; + Match(T__40); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorAddSubContext : ParserRuleContext { + public OperatorAddSubContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorAddSub; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorAddSub(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorAddSubContext operatorAddSub() { + OperatorAddSubContext _localctx = new OperatorAddSubContext(Context, State); + EnterRule(_localctx, 62, RULE_operatorAddSub); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 390; + _la = TokenStream.LA(1); + if ( !(_la==T__41 || _la==T__42) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorMulDivModContext : ParserRuleContext { + public OperatorMulDivModContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorMulDivMod; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorMulDivMod(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorMulDivModContext operatorMulDivMod() { + OperatorMulDivModContext _localctx = new OperatorMulDivModContext(Context, State); + EnterRule(_localctx, 64, RULE_operatorMulDivMod); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 392; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 263882790666240L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorBitwiseContext : ParserRuleContext { + public OperatorBitwiseContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorBitwise; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorBitwise(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorBitwiseContext operatorBitwise() { + OperatorBitwiseContext _localctx = new OperatorBitwiseContext(Context, State); + EnterRule(_localctx, 66, RULE_operatorBitwise); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 394; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 8725724278030336L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorUnaryContext : ParserRuleContext { + public OperatorUnaryContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorUnary; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorUnary(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorUnaryContext operatorUnary() { + OperatorUnaryContext _localctx = new OperatorUnaryContext(Context, State); + EnterRule(_localctx, 68, RULE_operatorUnary); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 396; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 28156293764087808L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class OperatorPowerContext : ParserRuleContext { + public OperatorPowerContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_operatorPower; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitOperatorPower(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public OperatorPowerContext operatorPower() { + OperatorPowerContext _localctx = new OperatorPowerContext(Context, State); + EnterRule(_localctx, 70, RULE_operatorPower); + try { + EnterOuterAlt(_localctx, 1); + { + State = 398; + Match(T__54); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class NumberContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode INT() { return GetToken(LuaParser.INT, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode HEX() { return GetToken(LuaParser.HEX, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode FLOAT() { return GetToken(LuaParser.FLOAT, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode HEX_FLOAT() { return GetToken(LuaParser.HEX_FLOAT, 0); } + public NumberContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_number; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitNumber(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public NumberContext number() { + NumberContext _localctx = new NumberContext(Context, State); + EnterRule(_localctx, 72, RULE_number); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 400; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & -1152921504606846976L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public partial class StringContext : ParserRuleContext { + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode NORMALSTRING() { return GetToken(LuaParser.NORMALSTRING, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode CHARSTRING() { return GetToken(LuaParser.CHARSTRING, 0); } + [System.Diagnostics.DebuggerNonUserCode] public ITerminalNode LONGSTRING() { return GetToken(LuaParser.LONGSTRING, 0); } + public StringContext(ParserRuleContext parent, int invokingState) + : base(parent, invokingState) + { + } + public override int RuleIndex { get { return RULE_string; } } + [System.Diagnostics.DebuggerNonUserCode] + public override TResult Accept(IParseTreeVisitor visitor) { + ILuaVisitor typedVisitor = visitor as ILuaVisitor; + if (typedVisitor != null) return typedVisitor.VisitString(this); + else return visitor.VisitChildren(this); + } + } + + [RuleVersion(0)] + public StringContext @string() { + StringContext _localctx = new StringContext(Context, State); + EnterRule(_localctx, 74, RULE_string); + int _la; + try { + EnterOuterAlt(_localctx, 1); + { + State = 402; + _la = TokenStream.LA(1); + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & 1008806316530991104L) != 0)) ) { + ErrorHandler.RecoverInline(this); + } + else { + ErrorHandler.ReportMatch(this); + Consume(); + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + ErrorHandler.ReportError(this, re); + ErrorHandler.Recover(this, re); + } + finally { + ExitRule(); + } + return _localctx; + } + + public override bool Sempred(RuleContext _localctx, int ruleIndex, int predIndex) { + switch (ruleIndex) { + case 12: return exp_sempred((ExpContext)_localctx, predIndex); + } + return true; + } + private bool exp_sempred(ExpContext _localctx, int predIndex) { + switch (predIndex) { + case 0: return Precpred(Context, 9); + case 1: return Precpred(Context, 7); + case 2: return Precpred(Context, 6); + case 3: return Precpred(Context, 5); + case 4: return Precpred(Context, 4); + case 5: return Precpred(Context, 3); + case 6: return Precpred(Context, 2); + case 7: return Precpred(Context, 1); + } + return true; + } + + private static int[] _serializedATN = { + 4,1,67,405,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7,6,2,7, + 7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13,2,14,7,14, + 2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20,7,20,2,21,7,21, + 2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7,26,2,27,7,27,2,28,7,28, + 2,29,7,29,2,30,7,30,2,31,7,31,2,32,7,32,2,33,7,33,2,34,7,34,2,35,7,35, + 2,36,7,36,2,37,7,37,1,0,1,0,1,0,1,1,5,1,81,8,1,10,1,12,1,84,9,1,1,1,3, + 1,87,8,1,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, + 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2, + 1,2,1,2,1,2,1,2,1,2,3,2,127,8,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1, + 2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,1,2,3,2,153,8,2, + 3,2,155,8,2,1,3,1,3,1,3,1,3,1,3,1,4,1,4,1,4,1,4,1,4,5,4,167,8,4,10,4,12, + 4,170,9,4,1,5,1,5,3,5,174,8,5,1,6,1,6,3,6,178,8,6,1,6,3,6,181,8,6,1,7, + 1,7,1,7,1,7,1,8,1,8,1,8,5,8,190,8,8,10,8,12,8,193,9,8,1,8,1,8,3,8,197, + 8,8,1,9,1,9,1,9,5,9,202,8,9,10,9,12,9,205,9,9,1,10,1,10,1,10,5,10,210, + 8,10,10,10,12,10,213,9,10,1,11,1,11,1,11,5,11,218,8,11,10,11,12,11,221, + 9,11,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12, + 3,12,236,8,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1, + 12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1,12,1, + 12,1,12,1,12,1,12,1,12,1,12,1,12,5,12,270,8,12,10,12,12,12,273,9,12,1, + 13,1,13,5,13,277,8,13,10,13,12,13,280,9,13,1,14,1,14,4,14,284,8,14,11, + 14,12,14,285,1,15,1,15,1,15,1,15,1,15,3,15,293,8,15,1,16,1,16,1,16,1,16, + 1,16,1,16,3,16,301,8,16,1,16,5,16,304,8,16,10,16,12,16,307,9,16,1,17,1, + 17,1,17,1,17,1,17,1,17,3,17,315,8,17,1,18,1,18,3,18,319,8,18,1,18,1,18, + 1,19,1,19,3,19,325,8,19,1,19,1,19,1,19,3,19,330,8,19,1,20,1,20,1,20,1, + 21,1,21,3,21,337,8,21,1,21,1,21,1,21,1,21,1,22,1,22,1,22,3,22,346,8,22, + 1,22,3,22,349,8,22,1,23,1,23,3,23,353,8,23,1,23,1,23,1,24,1,24,1,24,1, + 24,5,24,361,8,24,10,24,12,24,364,9,24,1,24,3,24,367,8,24,1,25,1,25,1,25, + 1,25,1,25,1,25,1,25,1,25,1,25,1,25,3,25,379,8,25,1,26,1,26,1,27,1,27,1, + 28,1,28,1,29,1,29,1,30,1,30,1,31,1,31,1,32,1,32,1,33,1,33,1,34,1,34,1, + 35,1,35,1,36,1,36,1,37,1,37,1,37,0,1,24,38,0,2,4,6,8,10,12,14,16,18,20, + 22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68, + 70,72,74,0,8,2,0,1,1,11,11,1,0,35,40,1,0,42,43,1,0,44,47,1,0,48,52,3,0, + 43,43,50,50,53,54,1,0,60,63,1,0,57,59,428,0,76,1,0,0,0,2,82,1,0,0,0,4, + 154,1,0,0,0,6,156,1,0,0,0,8,168,1,0,0,0,10,173,1,0,0,0,12,175,1,0,0,0, + 14,182,1,0,0,0,16,186,1,0,0,0,18,198,1,0,0,0,20,206,1,0,0,0,22,214,1,0, + 0,0,24,235,1,0,0,0,26,274,1,0,0,0,28,281,1,0,0,0,30,292,1,0,0,0,32,300, + 1,0,0,0,34,314,1,0,0,0,36,318,1,0,0,0,38,329,1,0,0,0,40,331,1,0,0,0,42, + 334,1,0,0,0,44,348,1,0,0,0,46,350,1,0,0,0,48,356,1,0,0,0,50,378,1,0,0, + 0,52,380,1,0,0,0,54,382,1,0,0,0,56,384,1,0,0,0,58,386,1,0,0,0,60,388,1, + 0,0,0,62,390,1,0,0,0,64,392,1,0,0,0,66,394,1,0,0,0,68,396,1,0,0,0,70,398, + 1,0,0,0,72,400,1,0,0,0,74,402,1,0,0,0,76,77,3,2,1,0,77,78,5,0,0,1,78,1, + 1,0,0,0,79,81,3,4,2,0,80,79,1,0,0,0,81,84,1,0,0,0,82,80,1,0,0,0,82,83, + 1,0,0,0,83,86,1,0,0,0,84,82,1,0,0,0,85,87,3,12,6,0,86,85,1,0,0,0,86,87, + 1,0,0,0,87,3,1,0,0,0,88,155,5,1,0,0,89,90,3,18,9,0,90,91,5,2,0,0,91,92, + 3,22,11,0,92,155,1,0,0,0,93,155,3,28,14,0,94,155,3,14,7,0,95,155,5,3,0, + 0,96,97,5,4,0,0,97,155,5,56,0,0,98,99,5,5,0,0,99,100,3,2,1,0,100,101,5, + 6,0,0,101,155,1,0,0,0,102,103,5,7,0,0,103,104,3,24,12,0,104,105,5,5,0, + 0,105,106,3,2,1,0,106,107,5,6,0,0,107,155,1,0,0,0,108,109,5,8,0,0,109, + 110,3,2,1,0,110,111,5,9,0,0,111,112,3,24,12,0,112,155,1,0,0,0,113,114, + 3,6,3,0,114,115,3,8,4,0,115,116,3,10,5,0,116,117,5,6,0,0,117,155,1,0,0, + 0,118,119,5,10,0,0,119,120,5,56,0,0,120,121,5,2,0,0,121,122,3,24,12,0, + 122,123,5,11,0,0,123,126,3,24,12,0,124,125,5,11,0,0,125,127,3,24,12,0, + 126,124,1,0,0,0,126,127,1,0,0,0,127,128,1,0,0,0,128,129,5,5,0,0,129,130, + 3,2,1,0,130,131,5,6,0,0,131,155,1,0,0,0,132,133,5,10,0,0,133,134,3,20, + 10,0,134,135,5,12,0,0,135,136,3,22,11,0,136,137,5,5,0,0,137,138,3,2,1, + 0,138,139,5,6,0,0,139,155,1,0,0,0,140,141,5,13,0,0,141,142,3,16,8,0,142, + 143,3,42,21,0,143,155,1,0,0,0,144,145,5,14,0,0,145,146,5,13,0,0,146,147, + 5,56,0,0,147,155,3,42,21,0,148,149,5,14,0,0,149,152,3,20,10,0,150,151, + 5,2,0,0,151,153,3,22,11,0,152,150,1,0,0,0,152,153,1,0,0,0,153,155,1,0, + 0,0,154,88,1,0,0,0,154,89,1,0,0,0,154,93,1,0,0,0,154,94,1,0,0,0,154,95, + 1,0,0,0,154,96,1,0,0,0,154,98,1,0,0,0,154,102,1,0,0,0,154,108,1,0,0,0, + 154,113,1,0,0,0,154,118,1,0,0,0,154,132,1,0,0,0,154,140,1,0,0,0,154,144, + 1,0,0,0,154,148,1,0,0,0,155,5,1,0,0,0,156,157,5,15,0,0,157,158,3,24,12, + 0,158,159,5,16,0,0,159,160,3,2,1,0,160,7,1,0,0,0,161,162,5,17,0,0,162, + 163,3,24,12,0,163,164,5,16,0,0,164,165,3,2,1,0,165,167,1,0,0,0,166,161, + 1,0,0,0,167,170,1,0,0,0,168,166,1,0,0,0,168,169,1,0,0,0,169,9,1,0,0,0, + 170,168,1,0,0,0,171,172,5,18,0,0,172,174,3,2,1,0,173,171,1,0,0,0,173,174, + 1,0,0,0,174,11,1,0,0,0,175,177,5,19,0,0,176,178,3,22,11,0,177,176,1,0, + 0,0,177,178,1,0,0,0,178,180,1,0,0,0,179,181,5,1,0,0,180,179,1,0,0,0,180, + 181,1,0,0,0,181,13,1,0,0,0,182,183,5,20,0,0,183,184,5,56,0,0,184,185,5, + 20,0,0,185,15,1,0,0,0,186,191,5,56,0,0,187,188,5,21,0,0,188,190,5,56,0, + 0,189,187,1,0,0,0,190,193,1,0,0,0,191,189,1,0,0,0,191,192,1,0,0,0,192, + 196,1,0,0,0,193,191,1,0,0,0,194,195,5,22,0,0,195,197,5,56,0,0,196,194, + 1,0,0,0,196,197,1,0,0,0,197,17,1,0,0,0,198,203,3,32,16,0,199,200,5,11, + 0,0,200,202,3,32,16,0,201,199,1,0,0,0,202,205,1,0,0,0,203,201,1,0,0,0, + 203,204,1,0,0,0,204,19,1,0,0,0,205,203,1,0,0,0,206,211,5,56,0,0,207,208, + 5,11,0,0,208,210,5,56,0,0,209,207,1,0,0,0,210,213,1,0,0,0,211,209,1,0, + 0,0,211,212,1,0,0,0,212,21,1,0,0,0,213,211,1,0,0,0,214,219,3,24,12,0,215, + 216,5,11,0,0,216,218,3,24,12,0,217,215,1,0,0,0,218,221,1,0,0,0,219,217, + 1,0,0,0,219,220,1,0,0,0,220,23,1,0,0,0,221,219,1,0,0,0,222,223,6,12,-1, + 0,223,236,5,23,0,0,224,236,5,24,0,0,225,236,5,25,0,0,226,236,3,72,36,0, + 227,236,3,74,37,0,228,236,5,26,0,0,229,236,3,40,20,0,230,236,3,26,13,0, + 231,236,3,46,23,0,232,233,3,68,34,0,233,234,3,24,12,8,234,236,1,0,0,0, + 235,222,1,0,0,0,235,224,1,0,0,0,235,225,1,0,0,0,235,226,1,0,0,0,235,227, + 1,0,0,0,235,228,1,0,0,0,235,229,1,0,0,0,235,230,1,0,0,0,235,231,1,0,0, + 0,235,232,1,0,0,0,236,271,1,0,0,0,237,238,10,9,0,0,238,239,3,70,35,0,239, + 240,3,24,12,9,240,270,1,0,0,0,241,242,10,7,0,0,242,243,3,64,32,0,243,244, + 3,24,12,8,244,270,1,0,0,0,245,246,10,6,0,0,246,247,3,62,31,0,247,248,3, + 24,12,7,248,270,1,0,0,0,249,250,10,5,0,0,250,251,3,60,30,0,251,252,3,24, + 12,5,252,270,1,0,0,0,253,254,10,4,0,0,254,255,3,58,29,0,255,256,3,24,12, + 5,256,270,1,0,0,0,257,258,10,3,0,0,258,259,3,56,28,0,259,260,3,24,12,4, + 260,270,1,0,0,0,261,262,10,2,0,0,262,263,3,54,27,0,263,264,3,24,12,3,264, + 270,1,0,0,0,265,266,10,1,0,0,266,267,3,66,33,0,267,268,3,24,12,2,268,270, + 1,0,0,0,269,237,1,0,0,0,269,241,1,0,0,0,269,245,1,0,0,0,269,249,1,0,0, + 0,269,253,1,0,0,0,269,257,1,0,0,0,269,261,1,0,0,0,269,265,1,0,0,0,270, + 273,1,0,0,0,271,269,1,0,0,0,271,272,1,0,0,0,272,25,1,0,0,0,273,271,1,0, + 0,0,274,278,3,30,15,0,275,277,3,36,18,0,276,275,1,0,0,0,277,280,1,0,0, + 0,278,276,1,0,0,0,278,279,1,0,0,0,279,27,1,0,0,0,280,278,1,0,0,0,281,283, + 3,30,15,0,282,284,3,36,18,0,283,282,1,0,0,0,284,285,1,0,0,0,285,283,1, + 0,0,0,285,286,1,0,0,0,286,29,1,0,0,0,287,293,3,32,16,0,288,289,5,27,0, + 0,289,290,3,24,12,0,290,291,5,28,0,0,291,293,1,0,0,0,292,287,1,0,0,0,292, + 288,1,0,0,0,293,31,1,0,0,0,294,301,5,56,0,0,295,296,5,27,0,0,296,297,3, + 24,12,0,297,298,5,28,0,0,298,299,3,34,17,0,299,301,1,0,0,0,300,294,1,0, + 0,0,300,295,1,0,0,0,301,305,1,0,0,0,302,304,3,34,17,0,303,302,1,0,0,0, + 304,307,1,0,0,0,305,303,1,0,0,0,305,306,1,0,0,0,306,33,1,0,0,0,307,305, + 1,0,0,0,308,309,5,29,0,0,309,310,3,24,12,0,310,311,5,30,0,0,311,315,1, + 0,0,0,312,313,5,21,0,0,313,315,5,56,0,0,314,308,1,0,0,0,314,312,1,0,0, + 0,315,35,1,0,0,0,316,317,5,22,0,0,317,319,5,56,0,0,318,316,1,0,0,0,318, + 319,1,0,0,0,319,320,1,0,0,0,320,321,3,38,19,0,321,37,1,0,0,0,322,324,5, + 27,0,0,323,325,3,22,11,0,324,323,1,0,0,0,324,325,1,0,0,0,325,326,1,0,0, + 0,326,330,5,28,0,0,327,330,3,46,23,0,328,330,3,74,37,0,329,322,1,0,0,0, + 329,327,1,0,0,0,329,328,1,0,0,0,330,39,1,0,0,0,331,332,5,13,0,0,332,333, + 3,42,21,0,333,41,1,0,0,0,334,336,5,27,0,0,335,337,3,44,22,0,336,335,1, + 0,0,0,336,337,1,0,0,0,337,338,1,0,0,0,338,339,5,28,0,0,339,340,3,2,1,0, + 340,341,5,6,0,0,341,43,1,0,0,0,342,345,3,20,10,0,343,344,5,11,0,0,344, + 346,5,26,0,0,345,343,1,0,0,0,345,346,1,0,0,0,346,349,1,0,0,0,347,349,5, + 26,0,0,348,342,1,0,0,0,348,347,1,0,0,0,349,45,1,0,0,0,350,352,5,31,0,0, + 351,353,3,48,24,0,352,351,1,0,0,0,352,353,1,0,0,0,353,354,1,0,0,0,354, + 355,5,32,0,0,355,47,1,0,0,0,356,362,3,50,25,0,357,358,3,52,26,0,358,359, + 3,50,25,0,359,361,1,0,0,0,360,357,1,0,0,0,361,364,1,0,0,0,362,360,1,0, + 0,0,362,363,1,0,0,0,363,366,1,0,0,0,364,362,1,0,0,0,365,367,3,52,26,0, + 366,365,1,0,0,0,366,367,1,0,0,0,367,49,1,0,0,0,368,369,5,29,0,0,369,370, + 3,24,12,0,370,371,5,30,0,0,371,372,5,2,0,0,372,373,3,24,12,0,373,379,1, + 0,0,0,374,375,5,56,0,0,375,376,5,2,0,0,376,379,3,24,12,0,377,379,3,24, + 12,0,378,368,1,0,0,0,378,374,1,0,0,0,378,377,1,0,0,0,379,51,1,0,0,0,380, + 381,7,0,0,0,381,53,1,0,0,0,382,383,5,33,0,0,383,55,1,0,0,0,384,385,5,34, + 0,0,385,57,1,0,0,0,386,387,7,1,0,0,387,59,1,0,0,0,388,389,5,41,0,0,389, + 61,1,0,0,0,390,391,7,2,0,0,391,63,1,0,0,0,392,393,7,3,0,0,393,65,1,0,0, + 0,394,395,7,4,0,0,395,67,1,0,0,0,396,397,7,5,0,0,397,69,1,0,0,0,398,399, + 5,55,0,0,399,71,1,0,0,0,400,401,7,6,0,0,401,73,1,0,0,0,402,403,7,7,0,0, + 403,75,1,0,0,0,33,82,86,126,152,154,168,173,177,180,191,196,203,211,219, + 235,269,271,278,285,292,300,305,314,318,324,329,336,345,348,352,362,366, + 378 + }; + + public static readonly ATN _ATN = + new ATNDeserializer().Deserialize(_serializedATN); + + +} diff --git a/bot/src/Syntax/Parser/LuaVisitor.cs b/bot/src/Syntax/Parser/LuaVisitor.cs new file mode 100644 index 0000000..65da509 --- /dev/null +++ b/bot/src/Syntax/Parser/LuaVisitor.cs @@ -0,0 +1,470 @@ +// Unreachable code detected +#pragma warning disable 0162 +// The variable '...' is assigned but its value is never used +#pragma warning disable 0219 +// Missing XML comment for publicly visible type or member '...' +#pragma warning disable 1591 +// Ambiguous reference in cref attribute +#pragma warning disable 419 + +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Tree; + +namespace MoonsecDeobfuscator.Syntax.Parser; + +/// +/// This interface defines a complete generic visitor for a parse tree produced +/// by . +/// +/// The return type of the visit operation. +[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.13.2")] +[System.CLSCompliant(false)] +public interface ILuaVisitor : IParseTreeVisitor { + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitChunk([NotNull] LuaParser.ChunkContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitBlock([NotNull] LuaParser.BlockContext ctx); + /// + /// Visit a parse tree produced by the statSemi + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatSemi([NotNull] LuaParser.StatSemiContext context); + /// + /// Visit a parse tree produced by the statAssign + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatAssign([NotNull] LuaParser.StatAssignContext ctx); + /// + /// Visit a parse tree produced by the statCall + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatCall([NotNull] LuaParser.StatCallContext ctx); + /// + /// Visit a parse tree produced by the statLabel + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatLabel([NotNull] LuaParser.StatLabelContext context); + /// + /// Visit a parse tree produced by the statBreak + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatBreak([NotNull] LuaParser.StatBreakContext ctx); + /// + /// Visit a parse tree produced by the statGoto + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatGoto([NotNull] LuaParser.StatGotoContext context); + /// + /// Visit a parse tree produced by the statDo + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatDo([NotNull] LuaParser.StatDoContext ctx); + /// + /// Visit a parse tree produced by the statWhile + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatWhile([NotNull] LuaParser.StatWhileContext ctx); + /// + /// Visit a parse tree produced by the statRepeat + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatRepeat([NotNull] LuaParser.StatRepeatContext ctx); + /// + /// Visit a parse tree produced by the statIf + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatIf([NotNull] LuaParser.StatIfContext ctx); + /// + /// Visit a parse tree produced by the statNumericFor + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatNumericFor([NotNull] LuaParser.StatNumericForContext ctx); + /// + /// Visit a parse tree produced by the statGenericFor + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatGenericFor([NotNull] LuaParser.StatGenericForContext ctx); + /// + /// Visit a parse tree produced by the statFunction + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatFunction([NotNull] LuaParser.StatFunctionContext context); + /// + /// Visit a parse tree produced by the statLocalFunction + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatLocalFunction([NotNull] LuaParser.StatLocalFunctionContext context); + /// + /// Visit a parse tree produced by the statLocalDeclare + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitStatLocalDeclare([NotNull] LuaParser.StatLocalDeclareContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitIfstmt([NotNull] LuaParser.IfstmtContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitElseifstmt([NotNull] LuaParser.ElseifstmtContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitElsestmt([NotNull] LuaParser.ElsestmtContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitRetstat([NotNull] LuaParser.RetstatContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitLabel([NotNull] LuaParser.LabelContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFuncname([NotNull] LuaParser.FuncnameContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitVarlist([NotNull] LuaParser.VarlistContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitNamelist([NotNull] LuaParser.NamelistContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitExplist([NotNull] LuaParser.ExplistContext context); + /// + /// Visit a parse tree produced by the expNumber + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpNumber([NotNull] LuaParser.ExpNumberContext context); + /// + /// Visit a parse tree produced by the expTrue + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpTrue([NotNull] LuaParser.ExpTrueContext context); + /// + /// Visit a parse tree produced by the expOr + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpOr([NotNull] LuaParser.ExpOrContext context); + /// + /// Visit a parse tree produced by the expBitwise + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpBitwise([NotNull] LuaParser.ExpBitwiseContext context); + /// + /// Visit a parse tree produced by the expMulDivMod + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpMulDivMod([NotNull] LuaParser.ExpMulDivModContext context); + /// + /// Visit a parse tree produced by the expFalse + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpFalse([NotNull] LuaParser.ExpFalseContext context); + /// + /// Visit a parse tree produced by the expString + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpString([NotNull] LuaParser.ExpStringContext context); + /// + /// Visit a parse tree produced by the expPrefix + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpPrefix([NotNull] LuaParser.ExpPrefixContext context); + /// + /// Visit a parse tree produced by the expUnary + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpUnary([NotNull] LuaParser.ExpUnaryContext context); + /// + /// Visit a parse tree produced by the expAnd + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpAnd([NotNull] LuaParser.ExpAndContext context); + /// + /// Visit a parse tree produced by the expPow + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpPow([NotNull] LuaParser.ExpPowContext context); + /// + /// Visit a parse tree produced by the expFunction + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpFunction([NotNull] LuaParser.ExpFunctionContext context); + /// + /// Visit a parse tree produced by the expCompare + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpCompare([NotNull] LuaParser.ExpCompareContext context); + /// + /// Visit a parse tree produced by the expConcat + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpConcat([NotNull] LuaParser.ExpConcatContext context); + /// + /// Visit a parse tree produced by the expNil + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpNil([NotNull] LuaParser.ExpNilContext context); + /// + /// Visit a parse tree produced by the expAddSub + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpAddSub([NotNull] LuaParser.ExpAddSubContext context); + /// + /// Visit a parse tree produced by the expVarArg + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpVarArg([NotNull] LuaParser.ExpVarArgContext context); + /// + /// Visit a parse tree produced by the expTable + /// labeled alternative in . + /// + /// The parse tree. + /// The visitor result. + Result VisitExpTable([NotNull] LuaParser.ExpTableContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitPrefixexp([NotNull] LuaParser.PrefixexpContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFunctioncall([NotNull] LuaParser.FunctioncallContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitVarOrExp([NotNull] LuaParser.VarOrExpContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitVar([NotNull] LuaParser.VarContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitVarSuffix([NotNull] LuaParser.VarSuffixContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitNameAndArgs([NotNull] LuaParser.NameAndArgsContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitArgs([NotNull] LuaParser.ArgsContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFunctiondef([NotNull] LuaParser.FunctiondefContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFuncbody([NotNull] LuaParser.FuncbodyContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitParlist([NotNull] LuaParser.ParlistContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitTableconstructor([NotNull] LuaParser.TableconstructorContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFieldlist([NotNull] LuaParser.FieldlistContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitField([NotNull] LuaParser.FieldContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitFieldsep([NotNull] LuaParser.FieldsepContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorOr([NotNull] LuaParser.OperatorOrContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorAnd([NotNull] LuaParser.OperatorAndContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorComparison([NotNull] LuaParser.OperatorComparisonContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorStrcat([NotNull] LuaParser.OperatorStrcatContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorAddSub([NotNull] LuaParser.OperatorAddSubContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorMulDivMod([NotNull] LuaParser.OperatorMulDivModContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorBitwise([NotNull] LuaParser.OperatorBitwiseContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorUnary([NotNull] LuaParser.OperatorUnaryContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitOperatorPower([NotNull] LuaParser.OperatorPowerContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitNumber([NotNull] LuaParser.NumberContext context); + /// + /// Visit a parse tree produced by . + /// + /// The parse tree. + /// The visitor result. + Result VisitString([NotNull] LuaParser.StringContext context); +} diff --git a/bot/src/Syntax/Semantic/SymbolTable.cs b/bot/src/Syntax/Semantic/SymbolTable.cs new file mode 100644 index 0000000..f8301d7 --- /dev/null +++ b/bot/src/Syntax/Semantic/SymbolTable.cs @@ -0,0 +1,15 @@ +namespace MoonsecDeobfuscator.Syntax.Semantic; + +public class SymbolTable +{ + private readonly Dictionary _variables = []; + + public void Define(string name, VariableInfo variable) + { + _variables[name] = variable; + } + + public bool IsDefined(string name) => _variables.ContainsKey(name); + + public VariableInfo? GetVariable(string name) => _variables.GetValueOrDefault(name); +} \ No newline at end of file diff --git a/bot/src/Syntax/Semantic/SymbolTableBuilder.cs b/bot/src/Syntax/Semantic/SymbolTableBuilder.cs new file mode 100644 index 0000000..3b6d0d4 --- /dev/null +++ b/bot/src/Syntax/Semantic/SymbolTableBuilder.cs @@ -0,0 +1,147 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; +using MoonsecDeobfuscator.Ast.Statements; + +namespace MoonsecDeobfuscator.Syntax.Semantic; + +public class SymbolTableBuilder : AstWalker +{ + private readonly SymbolTable _symbols = new(); + + public static SymbolTable Build(Node node) + { + var visitor = new SymbolTableBuilder(); + visitor.Visit(node); + return visitor._symbols; + } + + public override void Visit(LocalDeclare node) + { + var names = node.Names; + var values = node.Values; + + VisitList(values); + + for (var i = 0; i < names.Count; i++) + { + var name = names[i].Value; + var expression = i < values.Count ? values[i] : values.LastOrDefault(); + + _symbols.Define(name, new VariableInfo + { + Value = expression, + DeclarationLocation = node + }); + } + } + + public override void Visit(Assign node) + { + var variables = node.Variables; + var values = node.Values; + + VisitList(values); + + for (var i = 0; i < variables.Count; i++) + { + var variable = variables[i]; + + if (variable is not Name name) + { + Visit(variable); + continue; + } + + var value = name.Value; + var expression = i < values.Count ? values[i] : values.LastOrDefault(); + + if (_symbols.IsDefined(value)) + { + var info = _symbols.GetVariable(value)!; + + info.Value = null; + info.AssignmentCount++; + } + else + { + _symbols.Define(value, new VariableInfo + { + DeclarationLocation = node, + Value = expression + }); + } + } + } + + public override void Visit(Name node) + { + var info = _symbols.GetVariable(node.Value); + + if (info != null) + info.ReadCount++; + } + + public override void Visit(ParameterList node) + { + foreach (var name in node.Names) + { + _symbols.Define(name.Value, new VariableInfo + { + DeclarationLocation = node + }); + } + } + + public override void Visit(Function node) + { + _symbols.Define(node.Name.Value, new VariableInfo + { + DeclarationLocation = node + }); + + Visit(node.Parameters); + Visit(node.Body); + } + + public override void Visit(LocalFunction node) + { + _symbols.Define(node.Name.Value, new VariableInfo + { + DeclarationLocation = node + }); + + Visit(node.Parameters); + Visit(node.Body); + } + + public override void Visit(NumericFor node) + { + Visit(node.InitialValue); + Visit(node.FinalValue); + + if (node.Step != null) + Visit(node.Step); + + _symbols.Define(node.IteratorName.Value, new VariableInfo + { + DeclarationLocation = node + }); + + Visit(node.Body); + } + + public override void Visit(GenericFor node) + { + VisitList(node.Expressions); + + foreach (var name in node.Names) + { + _symbols.Define(name.Value, new VariableInfo + { + DeclarationLocation = node + }); + } + + Visit(node.Body); + } +} \ No newline at end of file diff --git a/bot/src/Syntax/Semantic/VariableInfo.cs b/bot/src/Syntax/Semantic/VariableInfo.cs new file mode 100644 index 0000000..d847d9e --- /dev/null +++ b/bot/src/Syntax/Semantic/VariableInfo.cs @@ -0,0 +1,11 @@ +using MoonsecDeobfuscator.Ast; +using MoonsecDeobfuscator.Ast.Expressions; + +namespace MoonsecDeobfuscator.Syntax.Semantic; + +public class VariableInfo +{ + public Node? DeclarationLocation; + public Expression? Value; + public int AssignmentCount, ReadCount; +} \ No newline at end of file diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..c6b8750 --- /dev/null +++ b/render.yaml @@ -0,0 +1,9 @@ +services: + - type: web + name: medal-decompiler + env: docker + dockerfilePath: ./Dockerfile + plan: free + autoDeploy: true + # Render automatically sets $PORT, but we hardcode 3000 in Dockerfile +