Compare commits
8 Commits
3454bc9bc2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6412478668 | ||
|
|
c4a977a0b0 | ||
|
|
58a2308c10 | ||
|
|
0c3ff27dad | ||
|
|
28253d6806 | ||
|
|
ea1821480f | ||
|
|
22173f034a | ||
|
|
be401eeb15 |
248
01/project-hbj-attacker/.idea/editor.xml
generated
Normal file
248
01/project-hbj-attacker/.idea/editor.xml
generated
Normal file
@@ -0,0 +1,248 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BackendCodeEditorSettings">
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CDeclarationWithImplicitIntType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CommentTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConstevalIfIsAlwaysConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractClassWithoutSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAbstractVirtualFunctionCallInCtor/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAccessSpecifierWithNoDeclarations/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppAwaiterTypeIsNotClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBooleanIncrementExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatBadCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatLegacyCode/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatMixedArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooFewArgs/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppBoostFormatTooManyArgs/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCVQualifierCanNotBeAppliedToReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassCanBeFinal/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassIsIncomplete/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeedsConstructorBecauseOfUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppClassNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCompileTimeConstantCanBeReplacedWithBooleanConstant/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConceptNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConditionalExpressionCanBeSimplified/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppConstValueFunctionReturnType/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppCoroutineCallResolveError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAArrayIndexOutOfBounds/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantConditions/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantFunctionResult/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAConstantParameter/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFADeletedPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAEndlessLoop/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInfiniteRecursion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAInvalidatedMemory/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALocalValueEscapesScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFALoopConditionNotUpdated/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAMemoryLeak/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANotInitializedField/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFANullDereference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFATimeOver/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableCode/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreachableFunctionCall/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnreadVariable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDFAUnusedValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesLocal/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationHidesUncapturedLocal/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclarationSpecifierWithoutDeclarators/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorDisambiguatedAsFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeclaratorUsedBeforeInitialization/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultCaseNotHandledInSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultInitializationWithNoUserConstructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultIsUsedAsIdentifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDefaultedSpecialMemberFunctionIsImplicitlyDeleted/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeletingVoidPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTemplateWithoutTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDependentTypeWithoutTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedEntity/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedOverridenMethod/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDeprecatedRegisterStorageClassSpecifier/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDereferenceOperatorLimitExceeded/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDiscardedPostfixOperatorResult/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenSyntaxError/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUndocumentedParameter/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppDoxygenUnresolvedReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEmptyDeclaration/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersOrder/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceCVQualifiersPlacement/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceDoStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceForStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceFunctionDeclarationStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceIfStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceNestedNamespacesStyle/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingDestructorStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceOverridingFunctionStyle/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceTypeAliasCodeStyle/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnforceWhileStatementBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityAssignedButNoRead/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEntityUsedOnlyInUnevaluatedContext/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEnumeratorNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEqualOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppEvaluationFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExplicitSpecializationInNonNamespaceScope/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppExpressionWithoutSideEffects/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalFunctionInFinalClass/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFinalNonOverridingVirtualFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForLoopCanBeReplacedWithWhile/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppForwardEnumDeclarationWithoutUnderlyingType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionDoesntReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionResultShouldBeUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppFunctionalStyleCast/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHeaderHasBeenAlreadyIncluded/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHiddenFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppHidingFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIdenticalOperandsInBinaryExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIfCanBeReplacedByConstexprIf/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppImplicitDefaultConstructorNotAvailable/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompatiblePointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIncompleteSwitchStatement/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInconsistentNaming/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppIntegralToPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppInvalidLineContinuation/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppJoinDeclarationAndAssignment/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLambdaCaptureNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLocalVariableWithNonTrivialDtorIsNeverUsed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppLongFloat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeConst/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberFunctionMayBeStatic/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMemberInitializersOrder/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMismatchedClassTags/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingIncludeGuard/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMissingKeywordThrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppModulePartitionWithSeveralPartitionUnits/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtAddressOfClassRValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtBindingRValueToLvalueReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtCopyElisionInCopyInitDeclarator/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtDoubleUserConversionInCopyInit/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtNotInitializedStaticConstLocalVar/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMsExtReinterpretCastFromNullptr/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMultiCharacterWideLiteral/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMustBePublicVirtualToImplementInterface/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppMutableSpecifierOnReferenceMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNoDiscardExpression/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNodiscardFunctionWithoutReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExceptionSafeResourceAcquisition/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConversionOperator/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonExplicitConvertingConstructor/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineFunctionDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNonInlineVariableDefinitionInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppNotAllPathsReturnValue/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppObjectMemberMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppOutParameterMustBeWritten/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConst/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterMayBeConstPtrOrRef/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNamesMismatch/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPassValueParameterByConstReference/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerConversionDropsQualifiers/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPointerToIntegralConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPolymorphicClassWithNonVirtualPublicDestructor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyErroneousEmptyStatements/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUninitializedMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPossiblyUnintendedObjectSlicing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderIsNotIncluded/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrecompiledHeaderNotFound/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfBadFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfExtraArg/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfMissedArg/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrintfRiskyFormat/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppPrivateSpecialMemberFunctionIsNotImplemented/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRangeBasedForIncompatibleReference/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedefinitionOfDefaultArgumentInOverrideFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassAccessSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBaseClassInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantBooleanExpressionArgument/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantCastExpression/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantComplexityInComparison/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConditionalExpression/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantConstSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantControlFlowJump/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantDereferencingAndTakingAddress/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElaboratedTypeSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeyword/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantElseKeywordInsideCompoundStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyDeclaration/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantEmptyStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantExportKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantFwdClassOrEnumSpecifier/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantInlineSpecifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantLambdaParameterList/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantMemberInitializer/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantNamespaceDefinition/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantParentheses/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifier/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantQualifierADL/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnMemberAllocationFunction/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantStaticSpecifierOnThreadLocalLocalVariable/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateArguments/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTemplateKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantTypenameKeyword/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantVoidArgumentList/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRedundantZeroInitializerInAggregateInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReinterpretCastFromVoidPtr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppRemoveRedundantBraces/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceMemsetWithZeroInitialization/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReplaceTieWithStructuredBinding/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppReturnNoValueInNonVoidFunction/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSmartPointerVsMakeFunction/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSomeObjectMembersMightNotBeInitialized/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppSpecialFunctionWithoutNoexceptSpecification/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticAssertFailure/@EntryIndexedValue" value="ERROR" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticDataMemberInUnnamedStruct/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStaticSpecifierOnAnonymousNamespaceMember/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppStringLiteralToCharPointerConversion/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTabsAreDisallowed/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateArgumentsCanBeDeduced/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterNeverUsed/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTemplateParameterShadowing/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppThrowExpressionCanBeReplacedWithRethrow/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScope/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTooWideScopeInitStatement/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppTypeAliasNeverUsed/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedDependentBaseClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUninitializedNonStaticDataMember/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnionMemberOfReferenceType/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaEndRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnmatchedPragmaRegionDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnamedNamespaceInHeaderFile/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnnecessaryWhitespace/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnsignedZeroComparison/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUnusedIncludeDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAlgorithmWithCount/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAssociativeContains/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAuto/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseAutoForNumeric/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseElementsView/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseEraseAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseFamiliarTemplateSyntaxForGenericLambdas/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseRangeAlgorithm/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStdSize/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseStructuredBinding/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUseTypeTraitAlias/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUserDefinedLiteralSuffixDoesNotStartWithUnderscore/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppUsingResultOfAssignmentAsCondition/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVariableCanBeMadeConstexpr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionCallInsideCtor/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVirtualFunctionInFinalClass/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppVolatileParameterInDeclaration/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWarningDirective/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongIncludesOrder/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppWrongSlashesInIncludeDirective/@EntryIndexedValue" value="HINT" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroConstantCanBeReplacedWithNullptr/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=CppZeroValuedExpressionUsedAsNullPointer/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IdentifierTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||
</component>
|
||||
</project>
|
||||
120
01/project-hbj-attacker/Cargo.lock
generated
120
01/project-hbj-attacker/Cargo.lock
generated
@@ -2,6 +2,18 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
@@ -90,6 +102,23 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51876e3748c4a347fe65b906f2b1ae46a1e55a497b22c94c1f4f2c469ff7673a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.21.0"
|
||||
@@ -121,6 +150,12 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.9"
|
||||
@@ -142,6 +177,36 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
|
||||
dependencies = [
|
||||
"aliasable",
|
||||
"ouroboros_macro",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros_macro"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr2"
|
||||
version = "2.0.0"
|
||||
@@ -173,16 +238,33 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2-diagnostics"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project-hbj-attacker"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ctor",
|
||||
"dynasmrt",
|
||||
"goblin",
|
||||
"iced-x86",
|
||||
"libc",
|
||||
"libloading",
|
||||
"memmap2",
|
||||
"nix",
|
||||
"ouroboros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -194,6 +276,32 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.107"
|
||||
@@ -211,8 +319,20 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
@@ -7,9 +7,13 @@ edition = "2024"
|
||||
dynasmrt = "4.0.1"
|
||||
iced-x86 = { version = "1.21.0", features = ["code_asm"] }
|
||||
libc = "0.2.177"
|
||||
nix = { version = "0.30.1", features = ["ptrace", "uio"] }
|
||||
nix = { version = "0.30.1", features = ["ptrace", "uio", "signal"] }
|
||||
ctor = "0.6.0"
|
||||
libloading = "0.8.9"
|
||||
goblin = "0.10.3"
|
||||
memmap2 = "0.9.9"
|
||||
ouroboros = "0.18.5"
|
||||
anyhow = "1.0.100"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
mod map;
|
||||
mod processes;
|
||||
mod asm;
|
||||
mod injectors;
|
||||
mod elf;
|
||||
|
||||
pub use map::is_address_in_range;
|
||||
pub use processes::get_pid_by_name;
|
||||
pub use processes::read_memory_vm;
|
||||
pub use processes::write_memory_vm;
|
||||
pub use processes::write_memory_ptrace;
|
||||
pub use map::first_rw_segment;
|
||||
pub use map::module_base_address;
|
||||
pub use map::first_exec_segment;
|
||||
pub use map::*;
|
||||
pub use asm::assemble;
|
||||
pub use processes::*;
|
||||
pub use injectors::*;
|
||||
pub use elf::*;
|
||||
12
01/project-hbj-attacker/src/helper/asm.rs
Normal file
12
01/project-hbj-attacker/src/helper/asm.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
use iced_x86::code_asm::asm_traits::CodeAsmJmp;
|
||||
use iced_x86::{Instruction, code_asm::*};
|
||||
|
||||
pub fn assemble<F>(addr: u64, op: F) -> Result<Vec<u8>, Box<dyn std::error::Error>>
|
||||
where
|
||||
F: Fn(&mut CodeAssembler) -> Result<(), Box<dyn std::error::Error>>,
|
||||
{
|
||||
let mut asm = CodeAssembler::new(64)?;
|
||||
_ = op(&mut asm);
|
||||
Ok(asm.assemble(addr)?)
|
||||
}
|
||||
117
01/project-hbj-attacker/src/helper/elf.rs
Normal file
117
01/project-hbj-attacker/src/helper/elf.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use anyhow::{Context, bail};
|
||||
use goblin::elf::{Elf, ProgramHeader, Sym, program_header::PT_DYNAMIC, program_header::PT_LOAD, reloc::R_X86_64_JUMP_SLOT, Reloc};
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
use std::ops::Deref;
|
||||
use ouroboros::self_referencing;
|
||||
|
||||
|
||||
fn open_mem_map(path: &str) -> Result<Mmap, Box<dyn std::error::Error>> {
|
||||
let file = File::open(path)?;
|
||||
unsafe { Ok(Mmap::map(&file)?) }
|
||||
}
|
||||
|
||||
#[self_referencing]
|
||||
pub struct ExecuteLinkFile {
|
||||
data: Vec<u8>,
|
||||
|
||||
#[borrows(data)]
|
||||
#[covariant]
|
||||
elf: Elf<'this>
|
||||
}
|
||||
|
||||
impl ExecuteLinkFile {
|
||||
pub fn prase(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let data = open_mem_map(path)?.deref().to_owned();
|
||||
let s = ExecuteLinkFileTryBuilder {
|
||||
data,
|
||||
elf_builder: |data_ref| {
|
||||
Elf::parse(&data_ref)
|
||||
}
|
||||
}.try_build()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn get_loads(&self) -> Result<Vec<ProgramHeader>, Box<dyn std::error::Error>> {
|
||||
let loads = self.borrow_elf()
|
||||
.program_headers
|
||||
.iter()
|
||||
.filter_map(|ph| match ph.p_type {
|
||||
PT_LOAD => Some(ph.to_owned()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<ProgramHeader>>();
|
||||
|
||||
Ok(loads)
|
||||
}
|
||||
|
||||
pub fn get_dynamic(&self) -> Result<ProgramHeader, Box<dyn std::error::Error>> {
|
||||
let dynamic = self.borrow_elf()
|
||||
.program_headers
|
||||
.iter()
|
||||
.find(|ph| ph.p_type == PT_DYNAMIC)
|
||||
.context("No PT_DYNAMIC segment found")?;
|
||||
|
||||
Ok(dynamic.clone())
|
||||
}
|
||||
|
||||
pub fn get_rela_sym(&self, name: &str) -> Result<Reloc, Box<dyn std::error::Error>> {
|
||||
let rela_plt = self.borrow_elf().pltrelocs.iter();
|
||||
|
||||
let sym = rela_plt
|
||||
.filter(|rela| {
|
||||
matches!(rela.r_type, R_X86_64_JUMP_SLOT) // R_X86_64_JUMP_SLOT
|
||||
})
|
||||
.filter_map(|rela| {
|
||||
let sym_index = rela.r_sym;
|
||||
let Ok(sym) = self.get_dyn_sym(sym_index) else {
|
||||
return None;
|
||||
};
|
||||
let Ok(sym_name) = self.get_dyn_str(sym.st_name) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if sym_name == name { Some(rela) } else { None }
|
||||
})
|
||||
.collect::<Vec<Reloc>>();
|
||||
|
||||
let first = sym
|
||||
.first()
|
||||
.context(format!("No symbol found with name {}", name))?;
|
||||
|
||||
Ok(first.clone())
|
||||
}
|
||||
|
||||
pub fn get_dyn_sym(&self, location: usize) -> Result<Sym, Box<dyn std::error::Error>> {
|
||||
let dyn_sym = self.borrow_elf()
|
||||
.dynsyms
|
||||
.get(location)
|
||||
.context(format!("No symbol found at location {}", location))?;
|
||||
|
||||
Ok(dyn_sym.clone())
|
||||
}
|
||||
|
||||
pub fn prase_dyn_sym(&self, name: &str) -> Result<Sym, Box<dyn std::error::Error>> {
|
||||
let dyn_sym = self.borrow_elf()
|
||||
.dynsyms.iter()
|
||||
.find(|sym| self.get_dyn_str(sym.st_name).ok().as_deref() == Some(name))
|
||||
.context(format!("No symbol found with name {}", name))?;
|
||||
|
||||
Ok(dyn_sym.clone())
|
||||
}
|
||||
|
||||
pub fn get_dyn_str(&self, location: usize) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let str = self.borrow_elf()
|
||||
.dynstrtab
|
||||
.get_at(location)
|
||||
.context(format!("Could not get dynstr at location {}", location))?;
|
||||
|
||||
Ok(str.to_owned())
|
||||
}
|
||||
|
||||
pub fn get_e_type(&self) -> u16
|
||||
{
|
||||
self.borrow_elf().header.e_type
|
||||
}
|
||||
}
|
||||
213
01/project-hbj-attacker/src/helper/injectors.rs
Normal file
213
01/project-hbj-attacker/src/helper/injectors.rs
Normal file
@@ -0,0 +1,213 @@
|
||||
use std::ffi::CString;
|
||||
use std::fs;
|
||||
use iced_x86::code_asm::{eax, r10, r8, r9, rax, rbp, rcx, rdi, rdx, rsi, rsp};
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag};
|
||||
use nix::unistd::Pid;
|
||||
use crate::helper::{assemble, Process};
|
||||
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
pub fn inject1(proc: &Process, seg_rw: (u64, u64)) -> Result<(), Box<dyn std::error::Error>> // Simple injection
|
||||
{
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
let injected_data = "You are injected. \r\n";
|
||||
proc.write_memory_vm(seg_rw.0 as usize, &injected_data.as_bytes())?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write \"{}\" to {:#016x}",
|
||||
injected_data, seg_rw.0
|
||||
);
|
||||
|
||||
let injected_inst = assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rax, 1u64)?; // Syscall 1 (write)
|
||||
asm.mov(rdi, 1u64)?; // Fd 1 (STDOUT)
|
||||
asm.mov(rsi, seg_rw.0)?; // Buffer pointer (Here is rw segment in target)
|
||||
asm.mov(rdx, injected_data.as_bytes().len() as u64)?; // Buffer length
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.write_memory_ptrace(regs.rip as usize, &injected_inst)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write instructions to {:#016x}",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(proc.get_pid(), None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
proc.wait();
|
||||
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", regs.rip);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn inject2(proc: &Process, seg_rw: (u64, u64)) -> Result<(), Box<dyn std::error::Error>> // ld injection
|
||||
{
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
// Get the absolute path to our shared library
|
||||
let lib_path = fs::canonicalize("./target/debug/libproject_hbj_attacker.so")?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
// Start Inject
|
||||
let c_lib_path = CString::new(lib_path).unwrap();
|
||||
proc.write_memory_vm(seg_rw.0 as usize, c_lib_path.as_bytes_with_nul())?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write {} to {:#016x}",
|
||||
&c_lib_path.to_string_lossy(),
|
||||
seg_rw.0
|
||||
);
|
||||
|
||||
let Some(target_dlopen_addr) = proc.find_remote_proc("/usr/lib/libc.so.6", "dlopen") else {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"first rw segment not found",
|
||||
)));
|
||||
};
|
||||
|
||||
let injected_inst = assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rdi, seg_rw.0)?; // Param 1: Filename
|
||||
asm.mov(rsi, 2u64)?; // Param 2: Flag, 2(RTLD_NOW)
|
||||
asm.call(target_dlopen_addr)?; // Syscall interrupt
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.write_memory_ptrace(regs.rip as usize, &injected_inst)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write instructions to {:#016x}",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(proc.get_pid(), None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
proc.wait();
|
||||
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", regs.rip);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn inject3(proc: &Process, seg_rw: (u64, u64)) -> Result<i32, Box<dyn std::error::Error>> // thread inject
|
||||
{
|
||||
// Alloc rwx memory
|
||||
|
||||
let page_addr
|
||||
= proc.alloc_pages(1, (libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as u64)? as usize;
|
||||
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} allocated page is at {:#016x}",
|
||||
page_addr
|
||||
);
|
||||
|
||||
let injected_data = "[%d] I am the injected thread, I am running... \r\n";
|
||||
proc.write_memory_vm(
|
||||
page_addr + 0x200,
|
||||
&CString::new(injected_data).unwrap().as_bytes_with_nul(),
|
||||
)?;
|
||||
proc.write_memory_vm(page_addr + 0x300, &1i64.to_le_bytes())?;
|
||||
proc.write_memory_vm(page_addr + 0x308, &0u64.to_le_bytes())?;
|
||||
|
||||
let printf = proc.find_remote_proc("/usr/lib/libc.so.6", "printf").unwrap();
|
||||
|
||||
// Construct inject payload
|
||||
let injected_payload = assemble(page_addr as u64, |asm| {
|
||||
let mut target_label = asm.create_label();
|
||||
|
||||
asm.mov(rbp, rsp)?;
|
||||
asm.mov(rcx, 0u64)?;
|
||||
asm.set_label(&mut target_label)?;
|
||||
|
||||
asm.add(rcx, 1i32)?;
|
||||
asm.push(rcx)?;
|
||||
|
||||
asm.mov(rdi, (page_addr + 0x200) as u64)?;
|
||||
asm.mov(rsi, rcx)?;
|
||||
asm.call(printf)?;
|
||||
|
||||
asm.mov(rax, 35u64)?; // Syscall 35 (nano sleep)
|
||||
asm.mov(rdi, (page_addr + 0x300) as u64)?; // Req
|
||||
asm.mov(rsi, 0u64)?; //Rem
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
|
||||
asm.pop(rcx)?;
|
||||
asm.jmp(target_label)?; // Jmp back to loop
|
||||
Ok(())
|
||||
})?;
|
||||
proc.write_memory_vm(page_addr, &injected_payload)?;
|
||||
println!("{GREEN}[trace]{RESET} write payload to {:#016x}", page_addr);
|
||||
|
||||
// Start Trigger
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
|
||||
let injected_trigger = assemble(regs.rip as u64, |asm| {
|
||||
asm.mov(rax, 56u64)?; // Syscall 56 (clone)
|
||||
|
||||
asm.mov(
|
||||
rdi,
|
||||
(libc::CLONE_VM
|
||||
| libc::CLONE_FS
|
||||
| libc::CLONE_FILES
|
||||
| libc::CLONE_SIGHAND
|
||||
| libc::CLONE_THREAD) as u64,
|
||||
)?; // Flags
|
||||
asm.mov(rsi, (page_addr + 0x1000) as u64)?; // Stack top
|
||||
|
||||
asm.mov(rdx, 0u64)?; // parent_tid = NULL
|
||||
asm.mov(r10, 0u64)?; // child_tid = NULL
|
||||
asm.mov(r8, 0u64)?; // tls = NULL
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
asm.test(eax, eax)?; // Syscall returns zero?
|
||||
asm.jz(page_addr as u64)?;
|
||||
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.write_memory_ptrace(regs.rip as usize, &injected_trigger)?;
|
||||
println!("{GREEN}[trace]{RESET} write trigger to {:#016x}", regs.rip);
|
||||
|
||||
ptrace::cont(proc.get_pid(), None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
proc.wait();
|
||||
|
||||
let regs = ptrace::getregs(proc.get_pid())?;
|
||||
let pid_new_thread = Pid::from_raw(regs.rax as i32);
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", regs.rip);
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} new thread is {}, which will be suspend.",
|
||||
pid_new_thread
|
||||
);
|
||||
|
||||
ptrace::attach(pid_new_thread)?;
|
||||
waitpid(pid_new_thread, Some(WaitPidFlag::WUNTRACED))?;
|
||||
println!("{GREEN}[trace]{RESET} attached new thread.");
|
||||
|
||||
loop {
|
||||
let regs = ptrace::getregs(pid_new_thread)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} rip in new thread is {:#016x}.",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
if regs.rip >= page_addr as u64 && regs.rip < (page_addr + 0x1000) as u64 {
|
||||
println!("{GREEN}[trace]{RESET} rip in new thread return to inject payload.");
|
||||
break;
|
||||
}
|
||||
|
||||
ptrace::step(pid_new_thread, None)?;
|
||||
waitpid(pid_new_thread, Some(WaitPidFlag::WUNTRACED))?;
|
||||
}
|
||||
|
||||
Ok(pid_new_thread.as_raw())
|
||||
}
|
||||
@@ -1,90 +1,109 @@
|
||||
|
||||
pub fn is_address_in_range(addr: u64, range_strings: &Vec<&str>) -> bool {
|
||||
for range_str in range_strings {
|
||||
if let Some((start, end)) = parse_address_range(range_str) {
|
||||
if addr >= start && addr < end {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
use crate::helper::ExecuteLinkFile;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryRegion {
|
||||
pub start_addr: u64,
|
||||
pub end_addr: u64,
|
||||
pub perms: String,
|
||||
pub offset: Option<u64>,
|
||||
pub dev: Option<String>,
|
||||
pub inode: Option<u64>,
|
||||
pub pathname: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_address_range(range_str: &str) -> Option<(u64, u64)> {
|
||||
let parts: Vec<&str> = range_str.split_whitespace().collect();
|
||||
if parts.is_empty() {
|
||||
impl MemoryRegion {
|
||||
pub fn parse(line: &str) -> Option<Self> {
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let range_part = parts[0];
|
||||
|
||||
let range_parts: Vec<&str> = range_part.split('-').collect();
|
||||
if range_parts.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start_addr = u64::from_str_radix(range_parts[0], 16).ok()?;
|
||||
let end_addr = u64::from_str_radix(range_parts[1], 16).ok()?;
|
||||
|
||||
Some((start_addr, end_addr))
|
||||
let perms = parts[1].to_string();
|
||||
|
||||
let offset = parts.get(2).and_then(|s| u64::from_str_radix(s, 16).ok());
|
||||
let dev = parts.get(3).map(|s| s.to_string());
|
||||
let inode = parts.get(4).and_then(|s| s.parse::<u64>().ok());
|
||||
let pathname = parts.get(5).map(|s| s.to_string());
|
||||
|
||||
Some(Self {
|
||||
start_addr,
|
||||
end_addr,
|
||||
perms,
|
||||
offset,
|
||||
dev,
|
||||
inode,
|
||||
pathname,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_read_write(&self) -> bool {
|
||||
self.perms.starts_with("rw")
|
||||
}
|
||||
|
||||
pub fn is_executable(&self) -> bool {
|
||||
self.perms.contains('x')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_rw_segment(range_strings: &Vec<&str>) -> Option<(u64, u64)> {
|
||||
for range_str in range_strings {
|
||||
let parts: Vec<&str> = range_str.split_whitespace().collect();
|
||||
if parts.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let perms = parts[1];
|
||||
if perms.starts_with("rw") {
|
||||
if let Some((start, end)) = parse_address_range(range_str) {
|
||||
return Some((start, end));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryMap {
|
||||
regions: Vec<MemoryRegion>,
|
||||
}
|
||||
|
||||
pub fn first_exec_segment(range_strings: &Vec<&str>) -> Option<(u64, u64)> {
|
||||
for range_str in range_strings {
|
||||
let parts: Vec<&str> = range_str.split_whitespace().collect();
|
||||
if parts.len() < 2 {
|
||||
continue;
|
||||
impl MemoryMap {
|
||||
pub fn new(lines: &Vec<&str>) -> Self {
|
||||
let regions = lines
|
||||
.iter()
|
||||
.filter_map(|line| MemoryRegion::parse(line))
|
||||
.collect();
|
||||
Self { regions }
|
||||
}
|
||||
|
||||
let perms = parts[1];
|
||||
if perms.contains('x') {
|
||||
if let Some((start, end)) = parse_address_range(range_str) {
|
||||
return Some((start, end));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn module_base_address(range_strings: &Vec<&str>, module_name: &str) -> Option<u64> {
|
||||
let mut base_addr: Option<u64> = None;
|
||||
|
||||
for range_str in range_strings {
|
||||
let parts: Vec<&str> = range_str.split_whitespace().collect();
|
||||
if parts.len() < 6 {
|
||||
continue;
|
||||
pub fn first_rw_segment(&self, module: &str) -> Option<(u64, u64)> {
|
||||
self.regions
|
||||
.iter()
|
||||
.find(|r| r.is_read_write() && r.pathname.as_deref() == Some(module))
|
||||
.map(|r| (r.start_addr, r.end_addr))
|
||||
}
|
||||
|
||||
let path = parts.last().unwrap();
|
||||
pub fn first_exec_segment(&self, module: &str) -> Option<(u64, u64)> {
|
||||
self.regions
|
||||
.iter()
|
||||
.find(|r| r.is_executable() && r.pathname.as_deref() == Some(module))
|
||||
.map(|r| (r.start_addr, r.end_addr))
|
||||
}
|
||||
|
||||
if let Some(filename) = std::path::Path::new(path).file_name().and_then(|f| f.to_str()) {
|
||||
if filename.contains(module_name) {
|
||||
if let Some((start, _)) = parse_address_range(range_str) {
|
||||
base_addr = match base_addr {
|
||||
Some(current_min) => Some(current_min.min(start)),
|
||||
None => Some(start),
|
||||
pub fn module_base_address(&self, module: &str) -> Option<u64> {
|
||||
let elf = ExecuteLinkFile::prase(&module).ok()?;
|
||||
let loads = elf.get_loads().ok()?;
|
||||
let Some(first_load) = loads.first() else {
|
||||
return None;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Some(map_item) = self.regions.iter().find(|r| {
|
||||
r.offset.unwrap_or(0) == first_load.p_offset && r.pathname.as_deref() == Some(module)
|
||||
}) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(map_item.start_addr - first_load.p_vaddr)
|
||||
}
|
||||
|
||||
base_addr
|
||||
pub fn collect_module(&self, module: &str) -> Vec<MemoryRegion>
|
||||
{
|
||||
let r = self.regions.iter()
|
||||
.filter_map(|r| if r.pathname.as_deref() == Some(module) { Some(r.clone()) } else { None })
|
||||
.collect::<Vec<MemoryRegion>>();
|
||||
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,19 @@ use std::fs;
|
||||
use nix::sys::uio::{process_vm_readv, RemoteIoVec, process_vm_writev};
|
||||
use nix::unistd::Pid;
|
||||
use std::error::Error;
|
||||
use std::ffi::CString;
|
||||
use std::io::{IoSliceMut, IoSlice};
|
||||
use anyhow::Context;
|
||||
use goblin::elf64::{header, section_header};
|
||||
use nix::sys::ptrace;
|
||||
use std::mem;
|
||||
use iced_x86::code_asm::{r10, r8, r9, rax, rdi, rdx, rsi};
|
||||
|
||||
use libc::{dlsym, user_regs_struct, RTLD_NEXT};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
|
||||
use crate::helper::{assemble, ExecuteLinkFile};
|
||||
use crate::helper::map::MemoryMap;
|
||||
|
||||
fn list_processes() -> Result<HashMap<String, i32>, std::io::Error>
|
||||
{
|
||||
let mut processes = HashMap::<String, i32>::new();
|
||||
@@ -29,7 +39,6 @@ fn list_processes() -> Result<HashMap<String, i32>, std::io::Error>
|
||||
|
||||
if let Some(name) = name_path.split("/").last() {
|
||||
processes.insert(name.to_string(), pid);
|
||||
println!("{} -> {}", name, dir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +51,118 @@ pub fn get_pid_by_name(name: &str) -> Result<i32, std::io::Error>
|
||||
Ok(ps[name])
|
||||
}
|
||||
|
||||
pub fn read_memory_vm(pid: Pid, start_addr: usize, size: usize) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
pub struct Process
|
||||
{
|
||||
pid: Pid,
|
||||
map: MemoryMap,
|
||||
}
|
||||
|
||||
impl Process
|
||||
{
|
||||
fn write_unaligned_head(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let head_offset = addr % word_size;
|
||||
let aligned_addr = addr - head_offset;
|
||||
let orig_word = ptrace::read(pid, aligned_addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
|
||||
let copy_len = usize::min(word_size - head_offset, data.len());
|
||||
bytes[head_offset..head_offset + copy_len].copy_from_slice(&data[..copy_len]);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, aligned_addr as *mut libc::c_void, new_word)?;
|
||||
Ok(copy_len)
|
||||
}
|
||||
|
||||
fn write_full_word(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8]
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let mut arr = [0u8; size_of::<libc::c_long>()];
|
||||
arr.copy_from_slice(data);
|
||||
let val = libc::c_long::from_le_bytes(arr);
|
||||
ptrace::write(pid, addr as *mut libc::c_void, val)?;
|
||||
Ok(size_of::<libc::c_long>())
|
||||
}
|
||||
|
||||
fn write_unaligned_tail(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
_word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let orig_word = ptrace::read(pid, addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, addr as *mut libc::c_void, new_word)?;
|
||||
Ok(data.len())
|
||||
}
|
||||
|
||||
pub fn new(pid: Pid) -> Result<Self, Box<dyn Error>>
|
||||
{
|
||||
let maps = fs::read_to_string(format!("/proc/{}/maps", pid))?;
|
||||
let map = MemoryMap::new(&maps.lines().filter(|&line| !line.is_empty()).collect::<Vec<&str>>());
|
||||
|
||||
Ok(Self { pid, map, })
|
||||
}
|
||||
|
||||
pub fn wait(&self) -> Option<WaitStatus>
|
||||
{
|
||||
let f = waitpid(self.pid, Some(WaitPidFlag::WUNTRACED)).ok()?;
|
||||
|
||||
match f {
|
||||
WaitStatus::Stopped(stopped_pid, signal) => {
|
||||
println!("[DEBUG] PID {} stopped by signal: {:?}", stopped_pid, signal);
|
||||
}
|
||||
WaitStatus::Exited(exited_pid, status) => {
|
||||
println!("[DEBUG] PID {} exited with status: {}", exited_pid, status);
|
||||
}
|
||||
WaitStatus::Signaled(signaled_pid, signal, core_dump) => {
|
||||
println!("[DEBUG] PID {} killed by signal: {:?} (core dump: {})",
|
||||
signaled_pid, signal, core_dump);
|
||||
}
|
||||
WaitStatus::Continued(continued_pid) => {
|
||||
println!("[DEBUG] PID {} continued", continued_pid);
|
||||
}
|
||||
WaitStatus::StillAlive => {
|
||||
println!("[DEBUG] PID {} still alive", self.pid);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Some(f)
|
||||
}
|
||||
|
||||
pub fn get_pid(&self) -> Pid { self.pid.clone() }
|
||||
|
||||
pub fn get_exe(&self) -> Result<String, Box<dyn Error>>
|
||||
{
|
||||
let r = fs::read_link(format!("/proc/{}/exe", self.pid))?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn get_map_str(&self) -> Result<String, Box<dyn Error>>
|
||||
{
|
||||
let r = fs::read_to_string(format!("/proc/{}/maps", self.pid))?;
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn read_memory_vm(&self, start_addr: usize, size: usize) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
{
|
||||
let mut buffer = vec![0u8; size];
|
||||
|
||||
let mut local_iov = [IoSliceMut::new(&mut buffer)];
|
||||
@@ -52,7 +172,7 @@ pub fn read_memory_vm(pid: Pid, start_addr: usize, size: usize) -> Result<Vec<u8
|
||||
len: size,
|
||||
}];
|
||||
|
||||
let bytes_read = process_vm_readv(pid, &mut local_iov, &remote_iov)?;
|
||||
let bytes_read = process_vm_readv(self.pid, &mut local_iov, &remote_iov)?;
|
||||
|
||||
if bytes_read == size {
|
||||
Ok(buffer)
|
||||
@@ -60,9 +180,10 @@ pub fn read_memory_vm(pid: Pid, start_addr: usize, size: usize) -> Result<Vec<u8
|
||||
buffer.truncate(bytes_read);
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_memory_vm(pid: Pid, mut start_addr: usize, mut data: &[u8]) -> Result<usize, Box<dyn Error>> {
|
||||
pub fn write_memory_vm(&self, mut start_addr: usize, mut data: &[u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let mut total_written = 0usize;
|
||||
while !data.is_empty() {
|
||||
let local_iov = [IoSlice::new(data)];
|
||||
@@ -71,7 +192,7 @@ pub fn write_memory_vm(pid: Pid, mut start_addr: usize, mut data: &[u8]) -> Resu
|
||||
len: data.len(),
|
||||
}];
|
||||
|
||||
let written = process_vm_writev(pid, &local_iov, &remote_iov)?;
|
||||
let written = process_vm_writev(self.pid, &local_iov, &remote_iov)?;
|
||||
|
||||
if written == 0 {
|
||||
return Err(format!("process_vm_writev returned 0 (no progress) after writing {} bytes", total_written).into());
|
||||
@@ -83,10 +204,11 @@ pub fn write_memory_vm(pid: Pid, mut start_addr: usize, mut data: &[u8]) -> Resu
|
||||
}
|
||||
|
||||
Ok(total_written)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_memory_ptrace(pid: Pid, start_addr: usize, data: &[u8]) -> Result<usize, Box<dyn Error>> {
|
||||
let word_size = mem::size_of::<libc::c_long>();
|
||||
pub fn write_memory_ptrace(&self, start_addr: usize, data: &[u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let word_size = size_of::<libc::c_long>();
|
||||
if word_size == 0 {
|
||||
return Err("invalid word size".into());
|
||||
}
|
||||
@@ -96,65 +218,118 @@ pub fn write_memory_ptrace(pid: Pid, start_addr: usize, data: &[u8]) -> Result<u
|
||||
let mut written = 0usize;
|
||||
|
||||
if addr % word_size != 0 && !remaining.is_empty() {
|
||||
let n = write_unaligned_head(pid, addr, remaining, word_size)?;
|
||||
let n = Self::write_unaligned_head(self.pid, addr, remaining, word_size)?;
|
||||
addr += n;
|
||||
remaining = &remaining[n..];
|
||||
written += n;
|
||||
}
|
||||
|
||||
while remaining.len() >= word_size {
|
||||
let n = write_full_word(pid, addr, &remaining[..word_size])?;
|
||||
let n = Self::write_full_word(self.pid, addr, &remaining[..word_size])?;
|
||||
addr += n;
|
||||
remaining = &remaining[n..];
|
||||
written += n;
|
||||
}
|
||||
|
||||
if !remaining.is_empty() {
|
||||
let n = write_unaligned_tail(pid, addr, remaining, word_size)?;
|
||||
let n = Self::write_unaligned_tail(self.pid, addr, remaining, word_size)?;
|
||||
written += n;
|
||||
}
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
fn write_unaligned_head(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>> {
|
||||
let head_offset = addr % word_size;
|
||||
let aligned_addr = addr - head_offset;
|
||||
let orig_word = ptrace::read(pid, aligned_addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
|
||||
let copy_len = usize::min(word_size - head_offset, data.len());
|
||||
bytes[head_offset..head_offset + copy_len].copy_from_slice(&data[..copy_len]);
|
||||
let new_word = libc::c_long::from_ne_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, aligned_addr as *mut libc::c_void, new_word)?;
|
||||
Ok(copy_len)
|
||||
}
|
||||
|
||||
fn write_full_word(pid: Pid, addr: usize, data: &[u8]) -> Result<usize, Box<dyn Error>> {
|
||||
let mut arr = [0u8; mem::size_of::<libc::c_long>()];
|
||||
arr.copy_from_slice(data);
|
||||
let val = libc::c_long::from_ne_bytes(arr);
|
||||
ptrace::write(pid, addr as *mut libc::c_void, val)?;
|
||||
Ok(mem::size_of::<libc::c_long>())
|
||||
}
|
||||
|
||||
fn write_unaligned_tail(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
_word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>> {
|
||||
let orig_word = ptrace::read(pid, addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
let new_word = libc::c_long::from_ne_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, addr as *mut libc::c_void, new_word)?;
|
||||
Ok(data.len())
|
||||
}
|
||||
|
||||
pub fn find_remote_proc(
|
||||
&self,
|
||||
module: &str, // Full path of module, like '/usr/lib/libc.so.6'
|
||||
symbol: &str // Symbol name, like 'printf'
|
||||
) -> Option<u64>
|
||||
{
|
||||
let elf = ExecuteLinkFile::prase(module).ok()?;
|
||||
let sym = elf.prase_dyn_sym(symbol).ok()?;
|
||||
|
||||
let target_maps = fs::read_to_string(format!("/proc/{}/maps", self.pid)).ok()?;
|
||||
let base = MemoryMap::new(&target_maps.lines().collect::<Vec<&str>>()).module_base_address(module)?;
|
||||
|
||||
let is_undefined = sym.st_shndx == section_header::SHN_UNDEF as usize;
|
||||
|
||||
if !is_undefined && sym.st_value != 0 {
|
||||
return if elf.get_e_type() == header::ET_DYN {
|
||||
Some(base + sym.st_value)
|
||||
} else {
|
||||
// ET_EXEC or others: assume st_value is absolute
|
||||
Some(sym.st_value)
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_got_pointer_plt(&self, symbol: &str) -> Option<u64>
|
||||
{
|
||||
let exe = self.get_exe().ok()?;
|
||||
let elf = ExecuteLinkFile::prase(&exe).ok()?;
|
||||
|
||||
let r_sym = elf.get_rela_sym(symbol).ok()?;
|
||||
Some(r_sym.r_offset + self.map.module_base_address(&exe)?)
|
||||
}
|
||||
|
||||
pub fn execute_once_inplace<F>(
|
||||
&self,
|
||||
payload_builder: F
|
||||
)
|
||||
-> Result<user_regs_struct, Box<dyn Error>>
|
||||
where F: Fn(u64) -> Option<Vec<u8>>
|
||||
{
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
// Save context
|
||||
let regs = ptrace::getregs(self.pid)?;
|
||||
let payload = payload_builder(regs.rip).context("payload build failed")?;
|
||||
|
||||
let buffer = self.read_memory_vm(regs.rip as usize, payload.len() + 1)?;
|
||||
let instruction = [&payload as &[u8], &[0xccu8]].concat();
|
||||
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &instruction)?;
|
||||
println!("{GREEN}[trace]{RESET} write instructions to {:#016x}", regs.rip);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(self.pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
self.wait();
|
||||
|
||||
let r = ptrace::getregs(self.pid)?;
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", r.rip);
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &buffer)?;
|
||||
ptrace::setregs(self.pid, regs)?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn alloc_pages(&self, count: u64, permissions: u64)
|
||||
-> Result<u64, Box<dyn Error>>
|
||||
{
|
||||
// Alloc r-x private memory
|
||||
let r = self.execute_once_inplace(|addr| {
|
||||
let r = assemble(addr, |asm| {
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
|
||||
asm.mov(rdi, 0u64)?; // Addr
|
||||
asm.mov(rsi, 0x1000u64 * count)?; // Length, we alloc a page (4K)
|
||||
asm.mov(rdx, permissions, )?;
|
||||
asm.mov(r10, (libc::MAP_PRIVATE | libc::MAP_ANONYMOUS) as u64)?; // Private and anonymous
|
||||
asm.mov(r8, -1i64)?; // Fd (-1 because we want anonymous)
|
||||
asm.mov(r9, 0u64)?; // Offset
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
Ok(())
|
||||
}).ok()?;
|
||||
|
||||
Some(r)
|
||||
})?;
|
||||
|
||||
Ok(r.rax as u64)
|
||||
}
|
||||
}
|
||||
@@ -3,278 +3,44 @@
|
||||
mod helper;
|
||||
|
||||
use nix::sys::ptrace;
|
||||
use nix::sys::wait::waitpid;
|
||||
use nix::sys::signal::{Signal, kill};
|
||||
use nix::unistd::Pid;
|
||||
use std::arch::asm;
|
||||
use std::ffi::CString;
|
||||
|
||||
use helper::*;
|
||||
use iced_x86::code_asm::asm_traits::CodeAsmJmp;
|
||||
use iced_x86::{Instruction, code_asm::*};
|
||||
use libc::user_regs_struct;
|
||||
use iced_x86::code_asm::{eax, r8, r9, r10, rax, rbp, rcx, rdi, rdx, rsi, rsp};
|
||||
use libc::{RTLD_NEXT, c_void, dlsym};
|
||||
use libc::{ptrace, user_regs_struct};
|
||||
use std::fs;
|
||||
use std::io::BufRead;
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
fn inject1(
|
||||
pid: Pid,
|
||||
seg_rw: (u64, u64),
|
||||
regs: user_regs_struct,
|
||||
) -> Result<(), Box<dyn std::error::Error>> // Simple injection
|
||||
{
|
||||
let injected_data = "You are injected. \r\n";
|
||||
write_memory_vm(pid, seg_rw.0 as usize, &injected_data.as_bytes())?;
|
||||
|
||||
let mut asm = CodeAssembler::new(64)?;
|
||||
|
||||
asm.mov(rax, 1u64)?; // Syscall 1 (write)
|
||||
asm.mov(rdi, 1u64)?; // Fd 1 (STDOUT)
|
||||
asm.mov(rsi, seg_rw.0)?; // Buffer pointer (Here is rw segment in target)
|
||||
asm.mov(rdx, injected_data.as_bytes().len() as u64)?; // Buffer length
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
|
||||
let injected_inst = asm.assemble(regs.rip as u64)?;
|
||||
write_memory_ptrace(pid, regs.rip as usize, &injected_inst)?;
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(pid, None)?;
|
||||
waitpid(pid, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inject2(
|
||||
pid: Pid,
|
||||
seg_rw: (u64, u64),
|
||||
regs: user_regs_struct,
|
||||
) -> Result<(), Box<dyn std::error::Error>> // ld injection
|
||||
{
|
||||
// Get the absolute path to our shared library
|
||||
let lib_path = fs::canonicalize("./target/debug/libproject_hbj_attacker.so")?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let cpid = nix::unistd::getpid().to_string();
|
||||
|
||||
// Read our own process memory maps to find libc base address
|
||||
let self_maps = fs::read_to_string(format!("/proc/{}/maps", cpid))?;
|
||||
let self_map_lines = self_maps.lines().collect::<Vec<&str>>();
|
||||
let mut dlopen_offset: u64 = 0;
|
||||
|
||||
// Find libc base address in our own process
|
||||
let Some(libc_base_local) = module_base_address(&self_map_lines, "libc.so") else {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"libc not found",
|
||||
)));
|
||||
};
|
||||
|
||||
println!("{GREEN}[local]{RESET} libc base: {:#016x}", libc_base_local);
|
||||
|
||||
// Use dlsym to get the address of dlopen in our own process
|
||||
unsafe {
|
||||
let dlopen_addr_local = dlsym(RTLD_NEXT, b"dlopen\0".as_ptr() as *const _);
|
||||
// Calculate offset of dlopen from libc base in our process
|
||||
dlopen_offset = dlopen_addr_local as u64 - libc_base_local;
|
||||
}
|
||||
|
||||
println!(
|
||||
"{GREEN}[local]{RESET} dlopen offset = {:#016x}",
|
||||
dlopen_offset
|
||||
);
|
||||
|
||||
// Read target process memory maps to find its libc base address
|
||||
let target_maps = fs::read_to_string(format!("/proc/{}/maps", pid))?;
|
||||
let target_map_lines = target_maps.lines().collect::<Vec<&str>>();
|
||||
|
||||
// Find libc base address in target process
|
||||
let Some(libc_base_target) = module_base_address(&target_map_lines, "libc.so") else {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"libc not found",
|
||||
)));
|
||||
};
|
||||
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} libc base = {:#016x}",
|
||||
libc_base_target
|
||||
);
|
||||
|
||||
// Calculate dlopen address in target process using the same offset
|
||||
let target_dlopen_addr = libc_base_target + dlopen_offset;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} dlopen address = {:#016x}",
|
||||
target_dlopen_addr
|
||||
);
|
||||
|
||||
// Start Inject
|
||||
let c_lib_path = CString::new(lib_path).unwrap();
|
||||
write_memory_vm(pid, seg_rw.0 as usize, c_lib_path.as_bytes_with_nul())?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write {} to {:#016x}",
|
||||
&c_lib_path.to_string_lossy(),
|
||||
seg_rw.0
|
||||
);
|
||||
|
||||
let mut asm = CodeAssembler::new(64)?;
|
||||
asm.mov(rdi, seg_rw.0)?; // Param 1: Filename
|
||||
asm.mov(rsi, 2u64)?; // Param 2: Flag, 2(RTLD_NOW)
|
||||
asm.call(target_dlopen_addr)?; // Syscall interrupt
|
||||
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
let injected_inst = asm.assemble(regs.rip as u64)?;
|
||||
write_memory_ptrace(pid, regs.rip as usize, &injected_inst)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write instructions to {:#016x}",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} running...");
|
||||
waitpid(pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} int3!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inject3(
|
||||
pid: Pid,
|
||||
seg_rw: (u64, u64),
|
||||
regs: user_regs_struct,
|
||||
) -> Result<(), Box<dyn std::error::Error>> // thread inject
|
||||
{
|
||||
// Alloc rwx memory
|
||||
let mut asm = CodeAssembler::new(64)?;
|
||||
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
|
||||
asm.mov(rdi, 1u64)?; // Addr
|
||||
asm.mov(rsi, 4096u64)?; // Length, we alloc a page (4K)
|
||||
asm.mov(
|
||||
rdx,
|
||||
(libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC) as u64,
|
||||
)?; // Set protect to rwx
|
||||
asm.mov(r10, (libc::MAP_SHARED | libc::MAP_ANONYMOUS) as u64)?; // Private and anonymous
|
||||
asm.mov(r8, 01i64)?; // Fd (-1 because we want anonymous)
|
||||
asm.mov(r9, 0u64)?; // Offset
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
|
||||
let injected_inst = asm.assemble(regs.rip as u64)?;
|
||||
write_memory_ptrace(pid, regs.rip as usize, &injected_inst)?;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} write instructions to {:#016x}",
|
||||
regs.rip
|
||||
);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} running...");
|
||||
waitpid(pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} int3!");
|
||||
|
||||
let regs_after_map = ptrace::getregs(pid)?;
|
||||
let page_addr = regs_after_map.rax as usize;
|
||||
println!(
|
||||
"{GREEN}[trace]{RESET} allocated page is at {:#016x}",
|
||||
page_addr
|
||||
);
|
||||
|
||||
let injected_data = "I am injected thread, I am running... \r\n";
|
||||
write_memory_vm(pid, page_addr + 0x500, &injected_data.as_bytes())?;
|
||||
write_memory_vm(pid, page_addr + 0x600, &1i64.to_le_bytes())?;
|
||||
write_memory_vm(pid, page_addr + 0x608, &0u64.to_le_bytes())?;
|
||||
|
||||
asm = CodeAssembler::new(64)?;
|
||||
// Construct inject payload
|
||||
let mut target_label = asm.create_label();
|
||||
|
||||
asm.set_label(&mut target_label)?;
|
||||
asm.mov(rax, 1u64)?; // Syscall 1 (write)
|
||||
asm.mov(rdi, 1u64)?; // Fd 1 (STDOUT)
|
||||
asm.mov(rsi, (page_addr + 0x500) as u64)?; // Buffer pointer (Here is page_addr + 0x500)
|
||||
asm.mov(rdx, injected_data.as_bytes().len() as u64)?; // Buffer length
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
|
||||
asm.mov(rax, 35u64)?; // Syscall 35 (nano sleep)
|
||||
asm.mov(rdi, (page_addr + 0x600) as u64)?; // Req
|
||||
asm.mov(rsi, 0u64)?; //Rem
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
|
||||
asm.jmp(target_label)?; // Jmp back to loop
|
||||
|
||||
let injected_payload = asm.assemble(page_addr as u64)?;
|
||||
write_memory_vm(pid, page_addr, &injected_payload)?;
|
||||
println!("{GREEN}[trace]{RESET} write payload to {:#016x}", page_addr);
|
||||
|
||||
// Start Trigger
|
||||
let regs = ptrace::getregs(pid)?;
|
||||
|
||||
asm = CodeAssembler::new(64)?;
|
||||
|
||||
asm.mov(rax, 56u64)?; // Syscall 56 (clone)
|
||||
|
||||
asm.mov(
|
||||
rdi,
|
||||
(libc::CLONE_VM
|
||||
| libc::CLONE_FS
|
||||
| libc::CLONE_FILES
|
||||
| libc::CLONE_SIGHAND
|
||||
| libc::CLONE_THREAD) as u64,
|
||||
)?; // Flags
|
||||
asm.mov(rsi, (page_addr + 0x800) as u64)?; // Stack top
|
||||
|
||||
asm.mov(rdx, 0u64)?; // parent_tid = NULL
|
||||
asm.mov(r10, 0u64)?; // child_tid = NULL
|
||||
asm.mov(r8, 0u64)?; // tls = NULL
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
asm.test(eax, eax)?; // Syscall returns zero?
|
||||
asm.jz(page_addr as u64)?;
|
||||
|
||||
asm.int3()?; // (Important!!!) Use int3 interrupt to retrieve control flow
|
||||
|
||||
let injected_trigger = asm.assemble(regs.rip as u64)?;
|
||||
write_memory_ptrace(pid, regs.rip as usize, &injected_trigger)?;
|
||||
println!("{GREEN}[trace]{RESET} write trigger to {:#016x}", regs.rip);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(pid, None)?;
|
||||
waitpid(pid, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Find our target program
|
||||
let pid = Pid::from_raw(get_pid_by_name("target")?);
|
||||
let proc = Process::new(pid)?;
|
||||
|
||||
let target = fs::read_link(format!("/proc/{}/exe", pid))?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let content = fs::read_to_string(format!("/proc/{}/maps", pid))?;
|
||||
let lines: Vec<&str> = content
|
||||
.lines()
|
||||
.filter(|&line| !line.is_empty() && line.contains(&target))
|
||||
.collect();
|
||||
let exe = proc.get_exe()?;
|
||||
let maps = proc.get_map_str()?;
|
||||
let lines: Vec<&str> = maps.lines().filter(|&line| !line.is_empty()).collect();
|
||||
|
||||
for line in &lines {
|
||||
println!("{GREEN}[memory map]{RESET} {}", line);
|
||||
}
|
||||
|
||||
let Some(seg_rw) = first_rw_segment(&lines) else {
|
||||
let map = MemoryMap::new(&lines);
|
||||
|
||||
let Some(seg_rw) = map.first_rw_segment(&exe) else {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"first rw segment not found",
|
||||
)));
|
||||
};
|
||||
|
||||
let Some(seg_x) = first_exec_segment(&lines) else {
|
||||
let Some(seg_x) = map.first_exec_segment(&exe) else {
|
||||
return Err(Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"first exec segment not found",
|
||||
@@ -282,58 +48,39 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
};
|
||||
|
||||
ptrace::attach(pid)?;
|
||||
waitpid(pid, None)?;
|
||||
proc.wait();
|
||||
ptrace::step(pid, None)?;
|
||||
waitpid(pid, None)?;
|
||||
|
||||
// ↓ Old behavior, but maybe the process stay in their libraries forever ?
|
||||
|
||||
// loop{
|
||||
// // Single-stepping, so that RIP returns to the user space of the process itself,
|
||||
// // rather than in some other library
|
||||
// let regs = ptrace::getregs(pid)?;
|
||||
// if is_address_in_range(regs.rip, &lines)
|
||||
// {
|
||||
// println!("{GREEN}[trace]{RESET} Address: {:#016x}", regs.rip);
|
||||
// break;
|
||||
// }
|
||||
// println!("{GREEN}[trace]{RESET} Skipped: {:#016x}", regs.rip);
|
||||
// ptrace::step(pid, None)?;
|
||||
// waitpid(pid, None)?;
|
||||
//}
|
||||
proc.wait();
|
||||
|
||||
// Save context
|
||||
let regs = ptrace::getregs(pid)?; // Save current registers
|
||||
let buffer = read_memory_vm(pid, seg_x.0 as usize, 128)?; // Save current memory context
|
||||
let buffer_rw = read_memory_vm(pid, seg_rw.0 as usize, 128)?; // Save current rw memory
|
||||
let buffer = proc.read_memory_vm(seg_x.0 as usize, 4096)?; // Save current memory context
|
||||
let buffer_rw = proc.read_memory_vm(seg_rw.0 as usize, 4096)?; // Save current rw memory
|
||||
|
||||
println!("{GREEN}[trace]{RESET} Seg_x.0 is {:#016x}", seg_x.0);
|
||||
|
||||
write_memory_ptrace(pid, seg_x.0 as usize, &[0x90u8; 128])?;
|
||||
ptrace::setregs(pid, user_regs_struct {
|
||||
rip: seg_x.0,
|
||||
..regs
|
||||
})?;
|
||||
|
||||
// Do inject here
|
||||
|
||||
inject3(
|
||||
proc.write_memory_ptrace(seg_x.0 as usize, &[0x90u8; 4096])?;
|
||||
ptrace::setregs(
|
||||
pid,
|
||||
seg_rw,
|
||||
user_regs_struct {
|
||||
rip: seg_x.0,
|
||||
..regs
|
||||
},
|
||||
)?;
|
||||
|
||||
// Do inject here
|
||||
|
||||
let c = inject3(&proc, seg_rw)?;
|
||||
|
||||
// End inject logics
|
||||
|
||||
// Restore context
|
||||
ptrace::setregs(pid, regs)?;
|
||||
write_memory_ptrace(pid, seg_x.0 as usize, &buffer)?;
|
||||
write_memory_vm(pid, seg_rw.0 as usize, &buffer_rw)?;
|
||||
proc.write_memory_ptrace(seg_x.0 as usize, &buffer)?;
|
||||
proc.write_memory_vm(seg_rw.0 as usize, &buffer_rw)?;
|
||||
|
||||
ptrace::detach(pid, None)?;
|
||||
ptrace::detach(Pid::from_raw(c), None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
8
01/project-hbj-hook/.idea/.gitignore
generated
vendored
Normal file
8
01/project-hbj-hook/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
8
01/project-hbj-hook/.idea/modules.xml
generated
Normal file
8
01/project-hbj-hook/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/project-hbj-hook.iml" filepath="$PROJECT_DIR$/.idea/project-hbj-hook.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
11
01/project-hbj-hook/.idea/project-hbj-hook.iml
generated
Normal file
11
01/project-hbj-hook/.idea/project-hbj-hook.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
01/project-hbj-hook/.idea/vcs.xml
generated
Normal file
6
01/project-hbj-hook/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
227
01/project-hbj-hook/Cargo.lock
generated
Normal file
227
01/project-hbj-hook/Cargo.lock
generated
Normal file
@@ -0,0 +1,227 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51876e3748c4a347fe65b906f2b1ae46a1e55a497b22c94c1f4f2c469ff7673a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
"scroll",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59"
|
||||
dependencies = [
|
||||
"aliasable",
|
||||
"ouroboros_macro",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros_macro"
|
||||
version = "0.18.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plain"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2-diagnostics"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "project-hbj-hook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"goblin",
|
||||
"iced-x86",
|
||||
"libc",
|
||||
"memmap2",
|
||||
"nix",
|
||||
"ouroboros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add"
|
||||
dependencies = [
|
||||
"scroll_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scroll_derive"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
13
01/project-hbj-hook/Cargo.toml
Normal file
13
01/project-hbj-hook/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "project-hbj-hook"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
iced-x86 = { version = "1.21.0", features = ["code_asm"] }
|
||||
libc = "0.2.177"
|
||||
nix = { version = "0.30.1", features = ["ptrace", "uio", "signal"] }
|
||||
goblin = "0.10.3"
|
||||
memmap2 = "0.9.9"
|
||||
anyhow = "1.0.100"
|
||||
ouroboros = "0.18.5"
|
||||
38
01/project-hbj-hook/src/asm.rs
Normal file
38
01/project-hbj-hook/src/asm.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
// asm.rs
|
||||
|
||||
use std::error::Error;
|
||||
use iced_x86::{code_asm::*, Formatter, Instruction, NasmFormatter};
|
||||
|
||||
pub fn assemble<F>(addr: u64, op: F) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&mut CodeAssembler) -> Result<(), Box<dyn Error>>,
|
||||
{
|
||||
let mut asm = CodeAssembler::new(64)?;
|
||||
_ = op(&mut asm);
|
||||
Ok(asm.assemble(addr)?)
|
||||
}
|
||||
|
||||
pub trait InstructionFormat {
|
||||
fn fmt_line(&self, formatter: &mut dyn Formatter) -> Result<String, Box<dyn Error>>;
|
||||
fn fmt_line_default(&self) -> Result<String, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl InstructionFormat for Instruction {
|
||||
fn fmt_line(&self, formatter: &mut dyn Formatter) -> Result<String, Box<dyn Error>> {
|
||||
let mut asm_str = String::new();
|
||||
formatter.format(self, &mut asm_str);
|
||||
|
||||
Ok(format!(
|
||||
"{:#016x}[{:02}] {}",
|
||||
self.ip(),
|
||||
self.len(),
|
||||
asm_str
|
||||
))
|
||||
}
|
||||
|
||||
fn fmt_line_default(&self) -> Result<String, Box<dyn Error>> {
|
||||
let mut fmt = NasmFormatter::new();
|
||||
self.fmt_line(&mut fmt)
|
||||
}
|
||||
}
|
||||
122
01/project-hbj-hook/src/elf.rs
Normal file
122
01/project-hbj-hook/src/elf.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
// elf.rs
|
||||
|
||||
use anyhow::{Context};
|
||||
use goblin::elf::{Elf, ProgramHeader, Sym, program_header::PT_DYNAMIC, program_header::PT_LOAD, reloc::R_X86_64_JUMP_SLOT, Reloc};
|
||||
use memmap2::Mmap;
|
||||
use std::fs::File;
|
||||
use std::ops::Deref;
|
||||
use ouroboros::self_referencing;
|
||||
|
||||
fn open_mem_map(path: &str) -> Result<Mmap, Box<dyn std::error::Error>> {
|
||||
let file = File::open(path)?;
|
||||
unsafe { Ok(Mmap::map(&file)?) }
|
||||
}
|
||||
|
||||
#[self_referencing]
|
||||
pub struct ExecuteLinkFile {
|
||||
data: Vec<u8>,
|
||||
|
||||
#[borrows(data)]
|
||||
#[covariant]
|
||||
elf: Elf<'this>
|
||||
}
|
||||
|
||||
impl ExecuteLinkFile {
|
||||
pub fn prase(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let data = open_mem_map(path)?.deref().to_owned();
|
||||
let s = ExecuteLinkFileTryBuilder {
|
||||
data,
|
||||
elf_builder: |data_ref| {
|
||||
Elf::parse(&data_ref)
|
||||
}
|
||||
}.try_build()?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
pub fn get_loads(&self) -> Result<Vec<ProgramHeader>, Box<dyn std::error::Error>> {
|
||||
let loads = self.borrow_elf()
|
||||
.program_headers
|
||||
.iter()
|
||||
.filter_map(|ph| match ph.p_type {
|
||||
PT_LOAD => Some(ph.to_owned()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<ProgramHeader>>();
|
||||
|
||||
Ok(loads)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get_dynamic(&self) -> Result<ProgramHeader, Box<dyn std::error::Error>> {
|
||||
let dynamic = self.borrow_elf()
|
||||
.program_headers
|
||||
.iter()
|
||||
.find(|ph| ph.p_type == PT_DYNAMIC)
|
||||
.context("No PT_DYNAMIC segment found")?;
|
||||
|
||||
Ok(dynamic.clone())
|
||||
}
|
||||
|
||||
pub fn get_rela_sym(&self, name: &str) -> Result<Reloc, Box<dyn std::error::Error>> {
|
||||
let rela_plt = self.borrow_elf().pltrelocs.iter();
|
||||
|
||||
let sym = rela_plt
|
||||
.filter(|rela| {
|
||||
matches!(rela.r_type, R_X86_64_JUMP_SLOT) // R_X86_64_JUMP_SLOT
|
||||
})
|
||||
.filter_map(|rela| {
|
||||
let sym_index = rela.r_sym;
|
||||
let Ok(sym) = self.get_dyn_sym(sym_index) else {
|
||||
return None;
|
||||
};
|
||||
let Ok(sym_name) = self.get_dyn_str(sym.st_name) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if sym_name == name { Some(rela) } else { None }
|
||||
})
|
||||
.collect::<Vec<Reloc>>();
|
||||
|
||||
let first = sym
|
||||
.first()
|
||||
.context(format!("No symbol found with name {}", name))?;
|
||||
|
||||
Ok(first.clone())
|
||||
}
|
||||
|
||||
pub fn get_dyn_sym(&self, location: usize) -> Result<Sym, Box<dyn std::error::Error>> {
|
||||
let dyn_sym = self.borrow_elf()
|
||||
.dynsyms
|
||||
.get(location)
|
||||
.context(format!("No symbol found at location {}", location))?;
|
||||
|
||||
Ok(dyn_sym.clone())
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn prase_dyn_sym(&self, name: &str) -> Result<Sym, Box<dyn std::error::Error>> {
|
||||
let dyn_sym = self.borrow_elf()
|
||||
.dynsyms.iter()
|
||||
.find(|sym| self.get_dyn_str(sym.st_name).ok().as_deref() == Some(name))
|
||||
.context(format!("No symbol found with name {}", name))?;
|
||||
|
||||
Ok(dyn_sym.clone())
|
||||
}
|
||||
|
||||
pub fn get_dyn_str(&self, location: usize) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let str = self.borrow_elf()
|
||||
.dynstrtab
|
||||
.get_at(location)
|
||||
.context(format!("Could not get dynstr at location {}", location))?;
|
||||
|
||||
Ok(str.to_owned())
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get_e_type(&self) -> u16
|
||||
{
|
||||
self.borrow_elf().header.e_type
|
||||
}
|
||||
}
|
||||
163
01/project-hbj-hook/src/hooks.rs
Normal file
163
01/project-hbj-hook/src/hooks.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
// hooks.rs
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use crate::map::MemoryMap;
|
||||
use crate::processes::Process;
|
||||
use anyhow::Context;
|
||||
|
||||
use crate::asm::{assemble, InstructionFormat};
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const YELLOW: &str = "\x1b[33m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn plt_hook<F>(
|
||||
proc: &Process,
|
||||
map: &MemoryMap,
|
||||
symbol: &str,
|
||||
payload: F,
|
||||
) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&Process, u64, u64) -> Result<Vec<u8>, Box<dyn Error>>,
|
||||
{
|
||||
let bias = map.module_base_address(&proc.get_exe()?).unwrap_or(0);
|
||||
let got_item_ptr = proc
|
||||
.find_got_pointer_plt(symbol)
|
||||
.context("Unable to find symbol")?;
|
||||
|
||||
println!("{GREEN}[memory map]{RESET} Bias is {:#016x}", bias);
|
||||
|
||||
let got_item_byte: [u8; 8] = proc
|
||||
.read_memory_vm(got_item_ptr as usize, 8)?
|
||||
.try_into()
|
||||
.map_err(|_| "Failed to convert Vec to array")?;
|
||||
let got_item = u64::from_le_bytes(got_item_byte);
|
||||
println!("{GREEN}[memory map]{RESET} got_item = {:#016x}", got_item);
|
||||
|
||||
let page_addr = proc.alloc_pages(1, (libc::PROT_READ | libc::PROT_EXEC) as u64)?;
|
||||
println!(
|
||||
"{GREEN}[plt hook]{RESET} allocated page is at {:#016x}",
|
||||
page_addr
|
||||
);
|
||||
|
||||
let payload = payload(&proc, page_addr, got_item)?;
|
||||
if payload.len() > 0x1000 {
|
||||
return Err(Box::<dyn Error>::from("payload exceeds 0x1000 bytes"));
|
||||
}
|
||||
|
||||
proc.write_memory_ptrace(page_addr as usize, &payload)?;
|
||||
println!(
|
||||
"{GREEN}[plt hook]{RESET} wrote {} bytes of instructions/data to {:#016x}",
|
||||
payload.len(),
|
||||
page_addr
|
||||
);
|
||||
proc.write_memory_ptrace(got_item_ptr as usize, &page_addr.to_le_bytes())?;
|
||||
println!(
|
||||
"{GREEN}[plt hook]{RESET} rewrote got item at {:#016x} to {:#016x}, old value is {:#016x}",
|
||||
got_item_ptr, page_addr, got_item
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn inline_hook<F>(
|
||||
proc: &Process,
|
||||
module: &str,
|
||||
symbol: &str,
|
||||
payload: F, // With stdcall, the payload has to clean the stack. But that's uncommon.
|
||||
) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&Process, u64, u64) -> Result<Vec<u8>, Box<dyn Error>>,
|
||||
{
|
||||
let remote_addr = proc.find_remote_proc(module, symbol).context("Unable to find proc")?;
|
||||
|
||||
println!("{GREEN}[memory map]{RESET} remote proc addr = {:#016x}", remote_addr);
|
||||
|
||||
let page_addr = proc.alloc_pages(2, (libc::PROT_READ | libc::PROT_EXEC) as u64)?;
|
||||
println!(
|
||||
"{GREEN}[inline hook]{RESET} allocated page is at {:#016x}",
|
||||
page_addr
|
||||
);
|
||||
|
||||
let payload_addr = page_addr + 32;
|
||||
let gateway_addr = page_addr;
|
||||
|
||||
let payload = payload(&proc, payload_addr, gateway_addr)?;
|
||||
if payload.len() > 0x2000 - 32 { return Err(Box::<dyn Error>::from("payload exceeds limit bytes")); }
|
||||
proc.write_memory_ptrace(payload_addr as usize, &payload)?;
|
||||
println!("{GREEN}[inline hook]{RESET} wrote payload to {:#016x}", payload_addr);
|
||||
|
||||
let jmp_inst = assemble(remote_addr, |asm| {
|
||||
asm.jmp(payload_addr)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let (gateway_sz, gap_sz) = proc.disassemble(remote_addr, 128, |inst| {
|
||||
let mut sum_inst_size = 0u32;
|
||||
|
||||
for i in inst.iter() {
|
||||
println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?);
|
||||
if (sum_inst_size as usize) < jmp_inst.len() {
|
||||
sum_inst_size += i.len() as u32;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sum_inst_size as usize) < jmp_inst.len() {
|
||||
return Err(Box::<dyn Error>::from(
|
||||
"Unable to find a suitable instruction boundary.",
|
||||
));
|
||||
}
|
||||
|
||||
let boundary = remote_addr + sum_inst_size as u64;
|
||||
|
||||
// Moving instructions to other locations for execution is !NOT! always safe,
|
||||
// but for library functions, this usually works,
|
||||
// because the first few instructions are usually endbr64, push rbp or something like that.
|
||||
let mut gateway = proc.instruction_relocate(remote_addr, sum_inst_size as u64, gateway_addr)?;
|
||||
|
||||
println!("{GREEN}[inline hook]{RESET} instruction boundary located at {:#016x}", boundary);
|
||||
|
||||
gateway.append(&mut assemble(gateway_addr + gateway.len() as u64, |asm|{
|
||||
asm.jmp(boundary)?;
|
||||
Ok(())
|
||||
})?);
|
||||
|
||||
proc.write_memory_ptrace(gateway_addr as usize, &gateway)?;
|
||||
println!("{GREEN}[inline hook]{RESET} {} bytes of gateway code write to {:#016x}",gateway.len(), gateway_addr);
|
||||
Ok((gateway.len(), sum_inst_size))
|
||||
})?;
|
||||
|
||||
proc.disassemble(gateway_addr, gateway_sz as u64, |inst| {
|
||||
for i in inst.iter() {
|
||||
println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.write_memory_ptrace(remote_addr as usize, &vec![0x90u8; gap_sz as usize])?;
|
||||
proc.write_memory_ptrace(remote_addr as usize, &jmp_inst)?;
|
||||
|
||||
println!("{GREEN}[inline hook]{RESET} wrote springboard to {:#016x}", remote_addr);
|
||||
|
||||
proc.disassemble(remote_addr, gap_sz as u64, |inst| {
|
||||
for i in inst.iter() {
|
||||
println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?);
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
proc.disassemble(remote_addr + gap_sz as u64, 32, |inst| {
|
||||
for i in inst.iter() {
|
||||
println!("{GREEN}[disassemble]{RESET} {YELLOW}{}{RESET}", i.fmt_line_default()?);
|
||||
break;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
98
01/project-hbj-hook/src/main.rs
Normal file
98
01/project-hbj-hook/src/main.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
// main.rs
|
||||
|
||||
use std::error::Error;
|
||||
use anyhow::Context;
|
||||
use iced_x86::code_asm::*;
|
||||
use crate::map::MemoryMap;
|
||||
use crate::processes::{get_pid_by_name, Process};
|
||||
use nix::unistd::Pid;
|
||||
use libc::user_regs_struct;
|
||||
use nix::sys::ptrace;
|
||||
use crate::asm::assemble;
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
mod elf;
|
||||
mod map;
|
||||
mod processes;
|
||||
mod asm;
|
||||
mod hooks;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Find our target program
|
||||
let pid = Pid::from_raw(get_pid_by_name("target")?);
|
||||
let process = Process::new(pid)?;
|
||||
|
||||
let exe = process.get_exe()?;
|
||||
let maps = process.get_map_str()?;
|
||||
let lines: Vec<&str> = maps.lines().filter(|&line| !line.is_empty()).collect();
|
||||
|
||||
for line in &lines {
|
||||
println!("{GREEN}[memory map]{RESET} {}", line);
|
||||
}
|
||||
|
||||
let map = MemoryMap::new(&lines);
|
||||
|
||||
let seg_x = map.first_exec_segment(&exe).context("Can't find first exec segment")?;
|
||||
|
||||
ptrace::attach(pid)?;
|
||||
process.wait();
|
||||
ptrace::step(pid, None)?;
|
||||
process.wait();
|
||||
|
||||
// Save context
|
||||
let regs = ptrace::getregs(pid)?; // Save current registers
|
||||
|
||||
ptrace::setregs(
|
||||
pid,
|
||||
user_regs_struct {
|
||||
rip: seg_x.0,
|
||||
..regs
|
||||
},
|
||||
)?;
|
||||
|
||||
// Do inject here
|
||||
|
||||
hooks::inline_hook(&process, "/usr/lib/libc.so.6", "write", |_proc, addr, old| {
|
||||
let inst = assemble(addr, |asm| {
|
||||
asm.endbr64()?;
|
||||
asm.push(rdi)?;
|
||||
asm.push(rsi)?;
|
||||
asm.push(rdx)?;
|
||||
asm.mov(rdi, 1u64)?;
|
||||
asm.mov(rsi, addr + 0x800)?;
|
||||
asm.mov(rdx, 7u64)?;
|
||||
asm.call(old)?;
|
||||
asm.pop(rdx)?;
|
||||
asm.pop(rsi)?;
|
||||
asm.pop(rdi)?;
|
||||
|
||||
asm.call(old)?;
|
||||
|
||||
asm.mov(rdi, 1u64)?;
|
||||
asm.mov(rsi, addr + 0x810)?;
|
||||
asm.mov(rdx, 2u64)?;
|
||||
asm.call(old)?;
|
||||
|
||||
asm.ret()?;
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
let mut payload = Vec::from([0u8; 0x1000]);
|
||||
payload.splice(0..inst.len(), inst);
|
||||
payload.splice(0x800..(0x800 + 7), Vec::from("[hook] ".as_bytes()));
|
||||
payload.splice(0x810..(0x810 + 2), Vec::from("\r\n".as_bytes()));
|
||||
|
||||
Ok(payload)
|
||||
})?;
|
||||
|
||||
// End inject logics
|
||||
|
||||
// Restore context
|
||||
ptrace::setregs(pid, regs)?;
|
||||
ptrace::detach(pid, None)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
120
01/project-hbj-hook/src/map.rs
Normal file
120
01/project-hbj-hook/src/map.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
|
||||
// map.rs
|
||||
|
||||
use crate::elf::ExecuteLinkFile;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemoryRegion {
|
||||
pub start_addr: u64,
|
||||
pub end_addr: u64,
|
||||
pub perms: String,
|
||||
pub offset: Option<u64>,
|
||||
pub dev: Option<String>,
|
||||
pub inode: Option<u64>,
|
||||
pub pathname: Option<String>,
|
||||
}
|
||||
|
||||
impl MemoryRegion {
|
||||
pub fn parse(line: &str) -> Option<Self> {
|
||||
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||
if parts.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let range_part = parts[0];
|
||||
let range_parts: Vec<&str> = range_part.split('-').collect();
|
||||
if range_parts.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
let start_addr = u64::from_str_radix(range_parts[0], 16).ok()?;
|
||||
let end_addr = u64::from_str_radix(range_parts[1], 16).ok()?;
|
||||
|
||||
let perms = parts[1].to_string();
|
||||
|
||||
let offset = parts.get(2).and_then(|s| u64::from_str_radix(s, 16).ok());
|
||||
let dev = parts.get(3).map(|s| s.to_string());
|
||||
let inode = parts.get(4).and_then(|s| s.parse::<u64>().ok());
|
||||
let pathname = parts.get(5).map(|s| s.to_string());
|
||||
|
||||
Some(Self {
|
||||
start_addr,
|
||||
end_addr,
|
||||
perms,
|
||||
offset,
|
||||
dev,
|
||||
inode,
|
||||
pathname,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_read_write(&self) -> bool {
|
||||
self.perms.starts_with("rw")
|
||||
}
|
||||
|
||||
pub fn is_executable(&self) -> bool {
|
||||
self.perms.contains('x')
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryMap {
|
||||
regions: Vec<MemoryRegion>,
|
||||
}
|
||||
|
||||
impl MemoryMap {
|
||||
pub fn new(lines: &Vec<&str>) -> Self {
|
||||
let regions = lines
|
||||
.iter()
|
||||
.filter_map(|line| MemoryRegion::parse(line))
|
||||
.collect();
|
||||
Self { regions }
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn first_rw_segment(&self, module: &str) -> Option<(u64, u64)> {
|
||||
self.regions
|
||||
.iter()
|
||||
.find(|r| r.is_read_write() && r.pathname.as_deref() == Some(module))
|
||||
.map(|r| (r.start_addr, r.end_addr))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn first_exec_segment(&self, module: &str) -> Option<(u64, u64)> {
|
||||
self.regions
|
||||
.iter()
|
||||
.find(|r| r.is_executable() && r.pathname.as_deref() == Some(module))
|
||||
.map(|r| (r.start_addr, r.end_addr))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn module_base_address(
|
||||
&self,
|
||||
module: &str // Full path of module, like '/usr/lib/libc.so.6'
|
||||
) -> Option<u64> {
|
||||
let elf = ExecuteLinkFile::prase(&module).ok()?;
|
||||
let loads = elf.get_loads().ok()?;
|
||||
let Some(first_load) = loads.iter().find(|p| {
|
||||
p.is_executable()
|
||||
}) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(map_item) = self.regions.iter().find(|r| {
|
||||
r.offset.unwrap_or(0) == first_load.p_offset && r.pathname.as_deref() == Some(module) && r.is_executable()
|
||||
}) else {
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(map_item.start_addr - first_load.p_vaddr)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn collect_module(&self, module: &str) -> Vec<MemoryRegion>
|
||||
{
|
||||
let r = self.regions.iter()
|
||||
.filter_map(|r| if r.pathname.as_deref() == Some(module) { Some(r.clone()) } else { None })
|
||||
.collect::<Vec<MemoryRegion>>();
|
||||
|
||||
r
|
||||
}
|
||||
}
|
||||
376
01/project-hbj-hook/src/processes.rs
Normal file
376
01/project-hbj-hook/src/processes.rs
Normal file
@@ -0,0 +1,376 @@
|
||||
|
||||
// processes.rs
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
use anyhow::Context;
|
||||
use nix::sys::uio::{process_vm_readv, RemoteIoVec, process_vm_writev};
|
||||
use nix::unistd::Pid;
|
||||
use std::error::Error;
|
||||
|
||||
use std::io::{IoSliceMut, IoSlice};
|
||||
use goblin::elf64::{header, section_header};
|
||||
use iced_x86::code_asm::{r10, r8, r9, rax, rdi, rdx, rsi};
|
||||
use iced_x86::{BlockEncoder, BlockEncoderOptions, Decoder, DecoderOptions, Instruction, InstructionBlock};
|
||||
|
||||
use nix::sys::ptrace;
|
||||
use libc::{user_regs_struct};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use crate::asm::assemble;
|
||||
use crate::elf::ExecuteLinkFile;
|
||||
use crate::map::{MemoryMap};
|
||||
|
||||
const GREEN: &str = "\x1b[32m";
|
||||
const RESET: &str = "\x1b[0m";
|
||||
|
||||
fn list_processes() -> Result<HashMap<String, i32>, std::io::Error>
|
||||
{
|
||||
let mut processes = HashMap::<String, i32>::new();
|
||||
|
||||
let entries = fs::read_dir("/proc")?;
|
||||
let dirs = entries.filter_map(|e| {
|
||||
let e = e.ok()?;
|
||||
let path = e.path();
|
||||
if path.is_dir() {
|
||||
return path.file_name()?.to_str().map(|s| s.to_string());
|
||||
}
|
||||
None::<String>
|
||||
}).collect::<Vec<String>>();
|
||||
|
||||
for dir in dirs {
|
||||
let Ok(pid) = dir.parse::<i32>() else { continue };
|
||||
let pid_path = format!("/proc/{}/exe", dir);
|
||||
let Ok(name_path) = fs::read_link(&pid_path) else { continue };
|
||||
let name_path = name_path.to_string_lossy().to_string();
|
||||
|
||||
if let Some(name) = name_path.split("/").last() {
|
||||
processes.insert(name.to_string(), pid);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(processes)
|
||||
}
|
||||
|
||||
pub fn get_pid_by_name(name: &str) -> Result<i32, std::io::Error>
|
||||
{
|
||||
let ps = list_processes()?;
|
||||
Ok(ps[name])
|
||||
}
|
||||
|
||||
pub struct Process
|
||||
{
|
||||
pid: Pid,
|
||||
map: MemoryMap,
|
||||
}
|
||||
|
||||
impl Process
|
||||
{
|
||||
fn write_unaligned_head(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let head_offset = addr % word_size;
|
||||
let aligned_addr = addr - head_offset;
|
||||
let orig_word = ptrace::read(pid, aligned_addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
|
||||
let copy_len = usize::min(word_size - head_offset, data.len());
|
||||
bytes[head_offset..head_offset + copy_len].copy_from_slice(&data[..copy_len]);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, aligned_addr as *mut libc::c_void, new_word)?;
|
||||
Ok(copy_len)
|
||||
}
|
||||
|
||||
fn write_full_word(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8]
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let mut arr = [0u8; size_of::<libc::c_long>()];
|
||||
arr.copy_from_slice(data);
|
||||
let val = libc::c_long::from_le_bytes(arr);
|
||||
ptrace::write(pid, addr as *mut libc::c_void, val)?;
|
||||
Ok(size_of::<libc::c_long>())
|
||||
}
|
||||
|
||||
fn write_unaligned_tail(
|
||||
pid: Pid,
|
||||
addr: usize,
|
||||
data: &[u8],
|
||||
_word_size: usize,
|
||||
) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let orig_word = ptrace::read(pid, addr as *mut libc::c_void)?;
|
||||
let mut bytes = orig_word.to_ne_bytes();
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
let new_word = libc::c_long::from_le_bytes(bytes);
|
||||
|
||||
ptrace::write(pid, addr as *mut libc::c_void, new_word)?;
|
||||
Ok(data.len())
|
||||
}
|
||||
|
||||
pub fn new(pid: Pid) -> Result<Self, Box<dyn Error>>
|
||||
{
|
||||
let maps = fs::read_to_string(format!("/proc/{}/maps", pid))?;
|
||||
let map = MemoryMap::new(&maps.lines().filter(|&line| !line.is_empty()).collect::<Vec<&str>>());
|
||||
|
||||
Ok(Self { pid, map, })
|
||||
}
|
||||
|
||||
pub fn wait(&self) -> Option<WaitStatus>
|
||||
{
|
||||
let f = waitpid(self.pid, Some(WaitPidFlag::WUNTRACED)).ok()?;
|
||||
|
||||
match f {
|
||||
WaitStatus::Stopped(stopped_pid, signal) => {
|
||||
println!("[DEBUG] PID {} stopped by signal: {:?}", stopped_pid, signal);
|
||||
}
|
||||
WaitStatus::Exited(exited_pid, status) => {
|
||||
println!("[DEBUG] PID {} exited with status: {}", exited_pid, status);
|
||||
}
|
||||
WaitStatus::Signaled(signaled_pid, signal, core_dump) => {
|
||||
println!("[DEBUG] PID {} killed by signal: {:?} (core dump: {})",
|
||||
signaled_pid, signal, core_dump);
|
||||
}
|
||||
WaitStatus::Continued(continued_pid) => {
|
||||
println!("[DEBUG] PID {} continued", continued_pid);
|
||||
}
|
||||
WaitStatus::StillAlive => {
|
||||
println!("[DEBUG] PID {} still alive", self.pid);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Some(f)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get_pid(&self) -> Pid { self.pid.clone() }
|
||||
|
||||
pub fn get_exe(&self) -> Result<String, Box<dyn Error>>
|
||||
{
|
||||
let r = fs::read_link(format!("/proc/{}/exe", self.pid))?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn get_map_str(&self) -> Result<String, Box<dyn Error>>
|
||||
{
|
||||
let r = fs::read_to_string(format!("/proc/{}/maps", self.pid))?;
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn read_memory_vm(&self, start_addr: usize, size: usize) -> Result<Vec<u8>, Box<dyn Error>>
|
||||
{
|
||||
let mut buffer = vec![0u8; size];
|
||||
|
||||
let mut local_iov = [IoSliceMut::new(&mut buffer)];
|
||||
|
||||
let remote_iov = [RemoteIoVec {
|
||||
base: start_addr,
|
||||
len: size,
|
||||
}];
|
||||
|
||||
let bytes_read = process_vm_readv(self.pid, &mut local_iov, &remote_iov)?;
|
||||
|
||||
if bytes_read == size {
|
||||
Ok(buffer)
|
||||
} else {
|
||||
buffer.truncate(bytes_read);
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn write_memory_vm(&self, mut start_addr: usize, mut data: &[u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let mut total_written = 0usize;
|
||||
while !data.is_empty() {
|
||||
let local_iov = [IoSlice::new(data)];
|
||||
let remote_iov = [RemoteIoVec {
|
||||
base: start_addr,
|
||||
len: data.len(),
|
||||
}];
|
||||
|
||||
let written = process_vm_writev(self.pid, &local_iov, &remote_iov)?;
|
||||
|
||||
if written == 0 {
|
||||
return Err(format!("process_vm_writev returned 0 (no progress) after writing {} bytes", total_written).into());
|
||||
}
|
||||
|
||||
total_written += written;
|
||||
start_addr = start_addr.wrapping_add(written);
|
||||
data = &data[written..];
|
||||
}
|
||||
|
||||
Ok(total_written)
|
||||
}
|
||||
|
||||
pub fn write_memory_ptrace(&self, start_addr: usize, data: &[u8]) -> Result<usize, Box<dyn Error>>
|
||||
{
|
||||
let word_size = size_of::<libc::c_long>();
|
||||
if word_size == 0 {
|
||||
return Err("invalid word size".into());
|
||||
}
|
||||
|
||||
let mut addr = start_addr;
|
||||
let mut remaining = data;
|
||||
let mut written = 0usize;
|
||||
|
||||
if addr % word_size != 0 && !remaining.is_empty() {
|
||||
let n = Self::write_unaligned_head(self.pid, addr, remaining, word_size)?;
|
||||
addr += n;
|
||||
remaining = &remaining[n..];
|
||||
written += n;
|
||||
}
|
||||
|
||||
while remaining.len() >= word_size {
|
||||
let n = Self::write_full_word(self.pid, addr, &remaining[..word_size])?;
|
||||
addr += n;
|
||||
remaining = &remaining[n..];
|
||||
written += n;
|
||||
}
|
||||
|
||||
if !remaining.is_empty() {
|
||||
let n = Self::write_unaligned_tail(self.pid, addr, remaining, word_size)?;
|
||||
written += n;
|
||||
}
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn find_remote_proc(
|
||||
&self,
|
||||
module: &str, // Full path of module, like '/usr/lib/libc.so.6'
|
||||
symbol: &str // Symbol name, like 'printf'
|
||||
) -> Option<u64>
|
||||
{
|
||||
let elf = ExecuteLinkFile::prase(module).ok()?;
|
||||
let sym = elf.prase_dyn_sym(symbol).ok()?;
|
||||
|
||||
let target_maps = fs::read_to_string(format!("/proc/{}/maps", self.pid)).ok()?;
|
||||
let base = MemoryMap::new(&target_maps.lines().collect::<Vec<&str>>()).module_base_address(module)?;
|
||||
|
||||
let is_undefined = sym.st_shndx == section_header::SHN_UNDEF as usize;
|
||||
|
||||
if !is_undefined && sym.st_value != 0 {
|
||||
return if elf.get_e_type() == header::ET_DYN {
|
||||
Some(base + sym.st_value)
|
||||
} else {
|
||||
// ET_EXEC or others: assume st_value is absolute
|
||||
Some(sym.st_value)
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn find_got_pointer_plt(&self, symbol: &str) -> Option<u64>
|
||||
{
|
||||
let exe = self.get_exe().ok()?;
|
||||
let elf = ExecuteLinkFile::prase(&exe).ok()?;
|
||||
|
||||
let r_sym = elf.get_rela_sym(symbol).ok()?;
|
||||
Some(r_sym.r_offset + self.map.module_base_address(&exe)?)
|
||||
}
|
||||
|
||||
pub fn execute_once_inplace<F>(
|
||||
&self,
|
||||
payload_builder: F
|
||||
)
|
||||
-> Result<user_regs_struct, Box<dyn Error>>
|
||||
where F: Fn(u64) -> Option<Vec<u8>>
|
||||
{
|
||||
// Save context
|
||||
let regs = ptrace::getregs(self.pid)?;
|
||||
let payload = payload_builder(regs.rip).context("payload build failed")?;
|
||||
|
||||
let buffer = self.read_memory_vm(regs.rip as usize, payload.len() + 1)?;
|
||||
let instruction = [&payload as &[u8], &[0xccu8]].concat();
|
||||
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &instruction)?;
|
||||
println!("{GREEN}[trace]{RESET} write instructions to {:#016x}", regs.rip);
|
||||
|
||||
// Continue target
|
||||
ptrace::cont(self.pid, None)?;
|
||||
println!("{GREEN}[trace]{RESET} continue from {:#016x}", regs.rip);
|
||||
self.wait();
|
||||
|
||||
let r = ptrace::getregs(self.pid)?;
|
||||
println!("{GREEN}[trace]{RESET} int3 at {:#016x}", r.rip);
|
||||
|
||||
self.write_memory_ptrace(regs.rip as usize, &buffer)?;
|
||||
ptrace::setregs(self.pid, regs)?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn alloc_pages(&self, count: u64, permissions: u64)
|
||||
-> Result<u64, Box<dyn Error>>
|
||||
{
|
||||
// Alloc r-x private memory
|
||||
let r = self.execute_once_inplace(|addr| {
|
||||
let r = assemble(addr, |asm| {
|
||||
asm.mov(rax, 9u64)?; // Syscall 9 (mmap)
|
||||
|
||||
asm.mov(rdi, 0u64)?; // Addr
|
||||
asm.mov(rsi, 0x1000u64 * count)?; // Length, we alloc a page (4K)
|
||||
asm.mov(rdx, permissions, )?;
|
||||
asm.mov(r10, (libc::MAP_PRIVATE | libc::MAP_ANONYMOUS) as u64)?; // Private and anonymous
|
||||
asm.mov(r8, -1i64)?; // Fd (-1 because we want anonymous)
|
||||
asm.mov(r9, 0u64)?; // Offset
|
||||
|
||||
asm.syscall()?; // Syscall interrupt
|
||||
Ok(())
|
||||
}).ok()?;
|
||||
|
||||
Some(r)
|
||||
})?;
|
||||
|
||||
Ok(r.rax as u64)
|
||||
}
|
||||
|
||||
pub fn disassemble<F, T>(
|
||||
&self,
|
||||
addr: u64,
|
||||
size: u64,
|
||||
callback: F,
|
||||
) -> Result<T, Box<dyn Error>>
|
||||
where
|
||||
F: Fn(&[Instruction]) -> Result<T, Box<dyn Error>>,
|
||||
{
|
||||
let code_bytes = self.read_memory_vm(addr as usize, size as usize)?;
|
||||
let decoder = Decoder::with_ip(64, &code_bytes, addr, DecoderOptions::NONE);
|
||||
let instructions: Vec<Instruction> = decoder.into_iter().collect();
|
||||
let result = callback(&instructions)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
||||
pub fn instruction_relocate(&self, addr: u64, size: u64, new_addr: u64)
|
||||
-> Result<Vec<u8>, Box<dyn Error>>
|
||||
{
|
||||
let origin = self.read_memory_vm(addr as usize, size as usize)?;
|
||||
|
||||
let decoder = Decoder::with_ip(64, &origin, addr, DecoderOptions::NONE);
|
||||
let instructions: Vec<_> = decoder.into_iter().collect();
|
||||
|
||||
let block = InstructionBlock::new(&instructions, new_addr);
|
||||
let options = BlockEncoderOptions::RETURN_RELOC_INFOS;
|
||||
|
||||
let result = BlockEncoder::encode(64, block, options)
|
||||
.map_err(|e| format!("BlockEncoder failed: {}", e))?;
|
||||
|
||||
Ok(result.code_buffer.clone())
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -4,6 +4,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
pid_t pid = getpid();
|
||||
@@ -11,6 +12,7 @@ int main()
|
||||
|
||||
while(true)
|
||||
{
|
||||
sleep(0);
|
||||
usleep(1000 * 300);
|
||||
write(1, ".", 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user