-
Notifications
You must be signed in to change notification settings - Fork 2
/
psp-confuser.groovy
170 lines (150 loc) · 7.4 KB
/
psp-confuser.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
pipeline {
agent any
environment {
// << CHANGE THESE >>
TOOLNAME = "Seatbelt"
GITURL = "https://github.com/GhostPack/Seatbelt.git"
BRANCH = "master"
WORKDIR = "C:\\opt\\jenkins-psp"
PSP_OUTPUT = "${WORKDIR}\\Invoke-${TOOLNAME}.ps1"
OBS_PSP_OUTPUT = "${WORKDIR}\\Obs-Invoke-${TOOLNAME}.ps1"
// << CHANGE THESE >> - .NET Compile configs
CONFIG="Release"
PLATFORM="Any CPU"
DOTNETVERSION="v3.5"
DOTNETNUMBER="net35" // net35, net40, net452, net462, net5
// 3rd party tools
CHAMELEONPATH = "${WORKDIR}\\chameleon\\chameleon.py"
EMBEDDOTNETPATH = "${WORKDIR}\\embedDotNet.ps1"
PREPPSPPATH = "${WORKDIR}\\PSPprep.ps1"
TEMPLATEPATH = "${WORKDIR}\\template.ps1"
CONFUSERPREP = "${WORKDIR}\\confuserEx.ps1"
}
stages {
stage('Cleanup'){
steps{
deleteDir()
dir("${TOOLNAME}"){
deleteDir()
}
}
}
stage('Git-Clone'){
steps{
script {
checkout([
$class: 'GitSCM',
branches: [[name: "*/${BRANCH}"]],
userRemoteConfigs: [[url: "${GITURL}"]]
])
}
}
}
// Skip prep powersharppack if the tool already has public class/main function.
stage('Prep-PSP'){
steps{
powershell "${PREPPSPPATH} -inputDir ${WORKSPACE} -toolName ${TOOLNAME}"
}
}
// Try nuget, then dotnet (for net5.0++)
// TODO: what's this "msbuild PROJECT.sln /t:Restore /p:Configuration=Release"
stage('Nuget-Restore'){
steps{
script{
def slnPath = powershell(returnStdout: true, script: "(Get-ChildItem -Path ${WORKSPACE} -Include '${TOOLNAME}.sln' -Recurse).FullName")
env.SLNPATH = slnPath
try{
bat "nuget restore ${SLNPATH}"
}
catch(Exception e){
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
bat """dotnet restore ${SLNPATH} """
}
}
}
}
}
// Try msbuild, then dotnet (for net5.0++). TODO: Find dotnet build --configuration ${CONFIG} params for pdb removal and release.
stage('Compile'){
steps {
script{
try{
bat "\"${tool 'MSBuild_VS2019'}\\MSBuild.exe\" /p:Configuration=${CONFIG} \"/p:Platform=${PLATFORM}\" /maxcpucount:%NUMBER_OF_PROCESSORS% /nodeReuse:false /p:DebugType=None /p:DebugSymbols=false /p:TargetFrameworkMoniker=\".NETFramework,Version=${DOTNETVERSION}\" ${SLNPATH}"
}
catch(Exception e){
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
bat """dotnet build --configuration ${CONFIG} ${SLNPATH} """
}
}
}
}
}
// ConfuserEx only when it's not net5.0++. Only execute this stage when the dotnet version contains "v" ex. v3.5
stage('ConfuserEx'){
when {
expression { env.DOTNETVERSION.contains('v')}
}
steps{
script{
// Some projects have net45/net35, some projects doesn't. So many one-offs
def exePath = powershell(returnStdout: true, script: """
\$exeFiles = (Get-ChildItem -Path ${WORKSPACE} -Include '*.exe' -Recurse | Where-Object {\$_.DirectoryName -match 'release' -and \$_.DirectoryName -match 'bin' } ).FullName
if (\$exeFiles -match "${DOTNETNUMBER}"){
\$exeFiles.trim()
}
else{
(Get-ChildItem -Path ${WORKSPACE} -Include '*.exe' -Recurse | Where-Object {\$_.DirectoryName -match 'release'} )[0].FullName
}
""")
env.EXEPATH = exePath
// Continue on failure.
catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE'){
// Copy all dependency dlls to the same dir as the EXE file
powershell(returnStdout:true, script: """
\$dllFiles = (Get-ChildItem -Path ${WORKSPACE} -Include '*.dll' -Recurse).FullName
if (\$dllFiles -match "${DOTNETNUMBER}"){
\$dllFiles -match "${DOTNETNUMBER}" | copy-item -destination (split-path \"${EXEPATH}\".trim() -Resolve)
}
else{
\$dllFiles | copy-item -destination (split-path \"${EXEPATH}\".trim() -Resolve)
}
""")
// Generate confuserEx project file using `confuserEx.ps1` script
powershell(returnStdout:true, script:"${CONFUSERPREP} -exePath \"${EXEPATH}\".trim() -outDir ${WORKSPACE}\\Confused -level normal -toolName ${TOOLNAME} ")
// Run confuserEx with the project file generated above
bat "Confuser.CLI.exe ${WORKSPACE}\\Confused\\${TOOLNAME}.crproj"
echo "[!] ConfuserEx failed. Skipping Obfuscation."
}
}
}
}
stage('Create-PSP'){
steps{
script{
def exePath = powershell(returnStdout: true, script: "(Get-ChildItem -Path ${WORKSPACE} -Include '*.exe' -Recurse | Where-Object {\$_.DirectoryName -match 'Confused'} ).FullName")
env.EXEPATH = exePath
// If confuserEx failed, just use the regular bin.
if (env.EXEPATH == ''){
exePath = powershell(returnStdout: true, script: """
\$exeFiles = (Get-ChildItem -Path ${WORKSPACE} -Include '*.exe' -Recurse | Where-Object {\$_.DirectoryName -match 'release' -and \$_.DirectoryName -match 'bin' } ).FullName
if (\$exeFiles -match "${DOTNETNUMBER}"){
\$exeFiles.trim()
}
else{
(Get-ChildItem -Path ${WORKSPACE} -Include '*.exe' -Recurse | Where-Object {\$_.DirectoryName -match 'release'} )[0].FullName
}
""")
env.EXEPATH = exePath
}
// Beaware of environment variable created from ps in jenkins (exePath). Always .trim() INSIDE powershell.
powershell "${EMBEDDOTNETPATH} -inputFile \"${EXEPATH}\".trim() -outputFile ${PSP_OUTPUT} -templatePath ${TEMPLATEPATH} -toolName ${TOOLNAME}"
}
}
}
stage('Obfuscate-PSP'){
steps{
bat encoding: 'UTF-8', script: """python ${CHAMELEONPATH} -v -d -c -f -r -i -l 4 ${PSP_OUTPUT} -o ${OBS_PSP_OUTPUT}"""
}
}
}
}