Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Process struct for use with the ScriptCompilationSystem in RED4ext #79

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions include/RED4ext/CWideString.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
#pragma once

#include <stdint.h>
#include <wchar.h>

namespace RED4ext
{
struct CString;
struct CWideString
{
/// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 48 89 31 48 8B D9 48 89 71 08 48 85
CWideString(const char* aStr)
{
int length;

this->length = 0;
this->capacity = 0;
this->wstr = 0i64;
if (aStr)
{
length = -1i64;
do
++length;
while (aStr[length]);
this->length = length;
if (length)
{
Reserve(length);
int length = this->length;
for (int i = 0; i < this->length; length = this->length)
{
int64_t v7 = i++;
this->wstr[v7] = aStr[v7];
}
this->wstr[length] = 0;
}
}
}

/// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 48 89 31 48 8B D9 48 89 71 08 48 85
CWideString(const wchar_t *aWstr)
{
uint32_t strLength; // eax

this->length = 0;
this->capacity = 0;
this->wstr = 0i64;
if ( aWstr )
{
strLength = wcslen(aWstr);
this->length = strLength;
if ( strLength )
{
Reserve(strLength);
memmove(this->wstr, aWstr, 2i64 * this->length);
this->wstr[this->length] = 0;
}
}
}

/// @pattern 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 30 8B 02 48 8B F9 48 8B 72 08 89 44 24 20 8B 42 04 89
CWideString(CWideString& aWStr);

/// @pattern 8B 02 89 01 8B 42 04 89 41 04 48 8B 42 08 48 89 41 08 33 C0 48 89 02 48 89 42 08 48 8B C1 C3
CWideString(CWideString&& aCwstr)
{
this->length = aCwstr.length;
this->capacity = aCwstr.capacity;
this->wstr = aCwstr.wstr;
aCwstr.length = 0;
aCwstr.capacity = 0;
aCwstr.wstr = nullptr;
}

/// @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 33 F6 48 8B FA 8B 12 48 8B D9 89 11 89 71 04 48 89
CWideString(CWideString* a2)
{
uint32_t length;
length = a2->length;
this->length = 0;
this->capacity = 0;
this->wstr = 0i64;
if (length)
{
Reserve(length);
memmove(this->wstr, a2->wstr, 2i64 * a2->length);
this->wstr[this->length] = 0;
}
}

/// @pattern 48 89 5C 24 08 57 48 83 EC 20 33 FF 48 8B D9 48 89 39 48 89 79 08 85 D2 74 0C E8 41 03 00 00 48
CWideString(uint32_t aCapacity)
{
this->length = 0;
this->capacity = 0;
this->wstr = 0i64;
if (aCapacity)
{
Reserve(aCapacity);
*this->wstr = 0;
}
}

/// @pattern 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 56 48 83 EC 20 45 33 F6 41 8B F0 4C 89 31 48 8B
CWideString(const wchar_t* aWstr, uint32_t aLength)
{
int64_t length;
wchar_t* wstr;

length = aLength;
this->length = 0i64;
this->capacity = 0i64;
this->wstr = 0i64;
if (aWstr && aLength)
{
Reserve(aLength);
memmove(this->wstr, aWstr, 2 * length);
wstr = this->wstr;
this->length = length;
wstr[length] = 0;
}
}

/// @pattern 48 89 5C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B 79 08 48 8B F1 48 8D 4C 24 30 E8 E0 6B 5F FD
~CWideString();

/// @pattern 48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 48 83 EC 30 48 8B F1 8B EA 48 8D 4C 24 40 E8 3D
void Reserve(uint32_t aCapacity);

/// @pattern 33 D2 89 11 39 51 04 76 07 48 8B 41 08 66 89 10 C3
void Clear()
{
this->length = 0;
if (this->capacity)
*this->wstr = 0;
}

/// @pattern 48 8B 41 08 C3
const wchar_t* c_str() const noexcept
{
return wstr;
}

/// @pattern 8B 01 C3
uint32_t Length() const noexcept
{
return length;
}

/// @pattern 48 89 5C 24 10 56 48 83 EC 20 41 8B F0 48 8B C1 4D 85 C9 75 11 45 85 C0 0F 95 C0 48 8B 5C 24 38
int8_t FindMaybe(int start_i, int end_i, const wchar_t *needle, int needle_start, int needle_end) const;

/// @pattern 48 89 5C 24 08 57 48 83 EC 20 8B 02 48 8B D9 8B 49 04 48 8B FA 85 C0 74 62 3B C8 72 15 48 8B 52
RED4ext::CWideString * CopyFrom(const RED4ext::CWideString *a2);

/// @pattern 40 55 57 48 83 EC 48 8B EA 48 8B F9 39 51 04 0F 83 F4 00 00 00 48 89 5C 24 68 48 89 74 24 70 4C
void Resize(uint32_t aLength);

/// @pattern 48 8B 41 08 8B D2 48 8D 04 50 C3
wchar_t * GetWideChar(unsigned int index)
{
return &wstr[index];
}

/// @pattern 40 53 48 81 EC 40 04 00 00 48 8B D9 48 8B CA E8 EC 83 5C FD 48 8B C8 48 8D 54 24 40 41 B8 00 04
static CString* GetCString(CString* aStr, const CWideString* aWStr);

[[nodiscard]] const wchar_t* begin() const
{
return c_str();
}

[[nodiscard]] const wchar_t* end() const
{
return c_str() + Length();
}

uint32_t length; // 00
uint32_t capacity; // 04
wchar_t* wstr; // 08
};
} // namespace RED4ext
73 changes: 73 additions & 0 deletions include/RED4ext/Process-inl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#pragma once
Copy link
Owner

Choose a reason for hiding this comment

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

Please add the cpp file too.


#ifdef RED4EXT_STATIC_LIB
#include <RED4ext/Process.hpp>
#endif
#include <RED4ext/Relocation.hpp>
Comment on lines +5 to +6
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
#endif
#include <RED4ext/Relocation.hpp>
#endif
#include <RED4ext/Relocation.hpp>


// This file has been generated by zoltan (https://github.com/jac3km4/zoltan)

#define Process_CloseHandles_Addr 0x2C23B30
#define Process_Execute_Addr 0x2C23D70
#define Process_Execute_0_Addr 0x2C23DD0
#define Process_GetExitCode_Addr 0x2C23B60
#define Process_Process_Addr 0x2C23AA0
#define Process_ReadFromPipe_Addr 0x2C23B90
#define Process_Terminate_Addr 0x2C24040
#define Process_WaitUntilCompleted_Addr 0x2C240B0
Comment on lines +8 to +17
Copy link
Owner

Choose a reason for hiding this comment

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

Please move these to IDA script.


inline bool RED4ext::Process::CloseHandles()
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
inline bool RED4ext::Process::CloseHandles()
RED4EXT_INLINE bool RED4ext::Process::CloseHandles()

Same for the others.

{
using Process_CloseHandles_t = bool (*)(RED4ext::Process*);
RED4ext::RelocFunc<Process_CloseHandles_t> call(Process_CloseHandles_Addr);
return call(this);
}

inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::CWideString& a2,
const RED4ext::CString& a3, const RED4ext::Process::ExecutionFlags a4)
{
using Process_Execute_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::CWideString&,
const RED4ext::CString&, const RED4ext::Process::ExecutionFlags);
RED4ext::RelocFunc<Process_Execute_t> call(Process_Execute_Addr);
return call(this, a1, a2, a3, a4);
}

inline bool RED4ext::Process::Execute(const RED4ext::CString& a1, RED4ext::CWideString& a2,
const RED4ext::CWideString& a3,
const RED4ext::Process::ExecutionFlags a4)
{
using Process_Execute_0_t = bool (*)(RED4ext::Process*, const RED4ext::CString&, RED4ext::CWideString&,
const RED4ext::CWideString&, const RED4ext::Process::ExecutionFlags);
RED4ext::RelocFunc<Process_Execute_0_t> call(Process_Execute_0_Addr);
return call(this, a1, a2, a3, a4);
}

inline uint32_t RED4ext::Process::GetExitCode()
{
using Process_GetExitCode_t = uint32_t (*)(RED4ext::Process*);
RED4ext::RelocFunc<Process_GetExitCode_t> call(Process_GetExitCode_Addr);
return call(this);
}

inline void RED4ext::Process::ReadFromPipe(const RED4ext::Process::ReadFlags a1, const RED4ext::CString& a2,
RED4ext::CString& a3)
{
using Process_ReadFromPipe_t =
void (*)(RED4ext::Process*, const RED4ext::Process::ReadFlags, const RED4ext::CString&, RED4ext::CString&);
RED4ext::RelocFunc<Process_ReadFromPipe_t> call(Process_ReadFromPipe_Addr);
return call(this, a1, a2, a3);
}

inline bool RED4ext::Process::Terminate(const uint32_t a1, const bool a2)
{
using Process_Terminate_t = bool (*)(RED4ext::Process*, const uint32_t, const bool);
RED4ext::RelocFunc<Process_Terminate_t> call(Process_Terminate_Addr);
return call(this, a1, a2);
}

inline bool RED4ext::Process::WaitUntilCompleted(const uint32_t a1) const
{
using Process_WaitUntilCompleted_t = bool (*)(RED4ext::Process*, const uint32_t);
RED4ext::RelocFunc<Process_WaitUntilCompleted_t> call(Process_WaitUntilCompleted_Addr);
return call(this, a1);
}
113 changes: 113 additions & 0 deletions include/RED4ext/Process.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#pragma once

#include <RED4ext/CString.hpp>
#include <RED4ext/CWideString.hpp>
#include <RED4ext/Common.hpp>
#include <cstdint>
#include <minwinrt.h>

namespace RED4ext
{
struct Process
{
static constexpr uint32_t DefaultTimeout = 60000;

enum class ExecutionFlags : std::uint8_t
{
// unsets CREATE_NO_WINDOW
ShouldCreateWindow = 0x1,
// sets CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED in Process Creation Flags
BreakawayAndSuspend = 0x2,
// unsets bInheritHandles
NoInheritHandles = 0x4
};

enum class ReadFlags : std::uint8_t
{
// open & read regardless of other options
Unk1 = 0x1,
// opens file from name provided and writes output
WriteToFile = 0x2,
// writes output to CString
GetCString = 0x4
};
Comment on lines +15 to +33
Copy link
Owner

Choose a reason for hiding this comment

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

I remembered that we decided to use struct flags, e.g. https://github.com/WopsS/RED4ext.SDK/blob/master/include/RED4ext/RTTITypes.hpp#L117-L132, so please convert these a as well to be consistent.


/**
* @brief creates the read & write pipes, and handle information
*
* @param[in] aHandle The plugin's handle.
* @param[in] aPath The path to be added to the redscript compilation - can be a folder or a .reds file
*
* @return Returns true if the path was added is attached, false otherwise.
*
* @pattern 48 89 5C 24 08 57 48 83 EC 40 33 C0 C7 44 24 20 18 00 00 00 48 8D 91 08 20 00 00 48 89 81 00 20
Copy link
Owner

Choose a reason for hiding this comment

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

Please move these pattern in the IDA script.

*/
Process();

/// @pattern 40 53 48 83 EC 20 48 8B D9 48 8B 89 08 20 00 00 FF 15 ? ? 4B 00 48 8B 8B 00 20 00 00 48 83 C4
bool CloseHandles();

/**
* @brief Assigns the process's error code to this->errorCode
*
* @return Returns the error code
*
* @pattern 40 53 48 83 EC 20 48 8D 99 28 20 00 00 48 8B 89 10 20 00 00 48 8B D3 FF 15 ? ? 4B 00 8B 03 48
*/
DWORD GetExitCode();

/// @pattern 40 55 56 57 41 56 B8 68 20 00 00 E8 ? ? E7 FF 48 2B E0 49 8B E9 49 8B F0 8B FA 4C 8B F1 F6 C2
void ReadFromPipe(const ReadFlags aFlags, const CString& aFilename, CString& aStdOut);

/**
* @brief Converts aWorkingDirectory to a CWideString and calls Execute
*
* @param[in] aCommand The location of the executable
* @param[in] aArgs Arguments passed to the command
* @param[in] aWorkingDirectory The directory to execute the process from
* @param[in] aFlags Flags that alter the execution
*
* @return True if the process was started successfully
*
* @pattern 48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 40 48 8B FA 48 8B F1 48 8D 54 24 30 49 8B C9 49 8B D8
*/
bool Execute(const CString& aCommand, CWideString& aArgs, const CString& aWorkingDirectory,
const ExecutionFlags aFlags);

/**
* @brief Begins the proccess
*
* @param[in] aCommand The location of the executable
* @param[in] aArgs Arguments passed to the command
* @param[in] aWorkingDirectory The directory to execute the process from
* @param[in] aFlags Flags that alter the execution
*
* @return True if the process was started successfully
*
* @pattern 48 89 5C 24 10 48 89 74 24 18 55 57 41 54 41 56 41 57 48 8D 6C 24 B0 48 81 EC 50 01 00 00 0F 57
*/
bool Execute(const CString& aCommand, CWideString& aArgs, const CWideString& aWorkingDirectory,
const ExecutionFlags aFlags);

/// @pattern 48 89 5C 24 08 57 48 83 EC 20 48 8B D9 41 0F B6 F8 48 8B 89 10 20 00 00 FF 15 ? ? 4B 00 85 C0
bool Terminate(const uint32_t aExitCode, const bool aCloseHandles);

/// @pattern 48 83 EC 48 48 8B 89 10 20 00 00 FF 15 ? ? 4B 00 85 C0 74 4A 3D 02 01 00 00 74 3C FF 15 ? ?
bool WaitUntilCompleted(const uint32_t aTimeoutMS) const;

wchar_t command[0x1000]; // 0000
PHANDLE readPipe; // 2000
PHANDLE writePipe; // 2008
HANDLE handle; // 2010
HANDLE hThread; // 2018
uint64_t unk2; // 2020
DWORD errorCode; // 2028
};

// DEFINE_ENUM_FLAG_OPERATORS(Process::ExecutionFlags);
// DEFINE_ENUM_FLAG_OPERATORS(Process::ReadFlags);
Comment on lines +107 to +108
Copy link
Owner

Choose a reason for hiding this comment

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

If commented, just remove it.

} // namespace RED4ext

#ifdef RED4EXT_HEADER_ONLY
#include <RED4ext/Process-inl.hpp>
#endif