Solidity is a typed language, so it's aware of the types of function parameters. When you call a certain function on a contract, Solidity knows that the type of the first parameter is an address, and can decode it as such. ABI is automatically generated from the types specified in the Solidity source code.
For a simple case of just getting an address from this particular input data, you can just do something like this (in JS):
const input = '0x2293db5700000000000000000000000030823e060e8be429b34bd9192df9cad4b166a056';
const address = `0x${input.slice(-40)}`;
console.log(address); // 0x30823e060e8be429b34bd9192df9cad4b166a056
In other cases where you may want to decode other types of data, you can first slice of the first 4 bytes (8 hexadecimal characters), and use something like Ethers.js' ABI decoder:
import { defaultAbiCoder } from '@ethersproject/abi';
const input = '0x2293db5700000000000000000000000030823e060e8be429b34bd9192df9cad4b166a056';
const address = defaultAbiCoder.decode(['address'], input.slice(10));
console.log(address); // 0x30823e060e8be429b34bd9192df9cad4b166a056
You can replace address
with the type of the parameter, and if your contract function has multiple input parameters, simply add them to the array.